Skip to main content

I am looking for a simple C# that can download call recordings.

I have looked at https://github.com/ringcentral/RingCentral.Net

Set up a sandbox app made a test call and recorded it. But I am lacking in the ability to just have a simple app that downloads to a local folder on the computer it runs on.

Does anyone have something I can use?

Try this

static private async Task download_call_log_callrecording()
{
RestClient rc = new RestClient(RINGCENTRAL_CLIENTID, RINGCENTRAL_CLIENTSECRET, RINGCENTRAL_PRODUCTION);
await rc.Authorize(RINGCENTRAL_USERNAME, RINGCENTRAL_EXTENSION, RINGCENTRAL_PASSWORD);
var parameters = new ReadCompanyCallLogParameters();
parameters.dateFrom = "2021-09-05T00:00:00.000Z";
parameters.view = "Simple";
parameters.recordingType = "All";

var path = "recording_content/";
System.IO.Directory.CreateDirectory(path);
long timePerApiCall = 6000;

var resp = await rc.Restapi().Account().CallLog().List(parameters);
foreach (var record in resp.records)
{
Console.WriteLine("-----");
Console.WriteLine("Call recording: " + record.recording.contentUri);
var fileName = path + "call_" + record.recording.id + "_recording";
var start = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
var result = await rc.Restapi().Account().Recording(record.recording.id).Get();
if (result.contentType == "audio/mpeg")
{
fileName += ".mp3";
}
else // can check if "audio/x-wav"
{
fileName += ".wav";
}
var contentUrl = result.contentUri + "?access_token=" + rc.token.access_token;
WebClient webClient = new WebClient();
webClient.DownloadFile(contentUrl, fileName);
Console.WriteLine("Save recording file to the local machine.");
var end = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
var delay = (end - start) * 1000;
Console.WriteLine(delay);
if (delay < timePerApiCall)
{
Thread.Sleep((int)(timePerApiCall - delay));
}
}
}

ok so i got this put together


using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using RingCentral;

namespace Recordings
{
class Program
{
static void Main(string[] args)
{
// Display the number of command line arguments.
Console.WriteLine(args.Length);
}


const string RINGCENTRAL_CLIENTID = "0_m0q2SexxxxxxKNQ";
const string RINGCENTRAL_CLIENTSECRET = "S1xxxxxxxxxZMiFFHzzzzzrb_sWSjUg";
const bool RINGCENTRAL_PRODUCTION = false;

const string RINGCENTRAL_USERNAME = "15555555555";
const string RINGCENTRAL_PASSWORD = "Password123!";
const string RINGCENTRAL_EXTENSION = "101";

static private async Task download_call_log_callrecording()
{
RestClient rc = new RestClient(RINGCENTRAL_CLIENTID, RINGCENTRAL_CLIENTSECRET, RINGCENTRAL_PRODUCTION);
await rc.Authorize(RINGCENTRAL_USERNAME, RINGCENTRAL_EXTENSION, RINGCENTRAL_PASSWORD);
var parameters = new ReadCompanyCallLogParameters();
parameters.dateFrom = "2021-09-05T00:00:00.000Z";
parameters.view = "Simple";
parameters.recordingType = "All";

var path = "recording_content/";
System.IO.Directory.CreateDirectory(path);
long timePerApiCall = 6000;

var resp = await rc.Restapi().Account().CallLog().List(parameters);
foreach (var record in resp.records)
{
Console.WriteLine("-----");
Console.WriteLine("Call recording: " + record.recording.contentUri);
var fileName = path + "call_" + record.recording.id + "_recording";
var start = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
var result = await rc.Restapi().Account().Recording(record.recording.id).Get();
if (result.contentType == "audio/mpeg")
{
fileName += ".mp3";
}
else // can check if "audio/x-wav"
{
fileName += ".wav";
}
var contentUrl = result.contentUri + "?access_token=" + rc.token.access_token;
WebClient webClient = new WebClient();
webClient.DownloadFile(contentUrl, fileName);
Console.WriteLine("Save recording file to the local machine.");
var end = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
var delay = (end - start) * 1000;
Console.WriteLine(delay);
if (delay < timePerApiCall)
{
Thread.Sleep((int)(timePerApiCall - delay));
}
}
}
}
}


When I run it I get this in the Debug output


'Ring_ABS.exe' (CoreCLR: DefaultDomain): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App3.1.8System.Private.CoreLib.dll'.

'Ring_ABS.exe' (CoreCLR: clrhost): Loaded 'C:Usersmikeasource
eposRing_ABSinDebug
etcoreapp3.1Ring_ABS.dll'. Symbols loaded.

'Ring_ABS.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App3.1.8System.Runtime.dll'.

'Ring_ABS.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App3.1.8System.Console.dll'.

'Ring_ABS.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App3.1.8System.Threading.dll'.

'Ring_ABS.exe' (CoreCLR: clrhost): Loaded 'C:Program FilesdotnetsharedMicrosoft.NETCore.App3.1.8System.Runtime.Extensions.dll'.

The program '[36264] Ring_ABS.exe' has exited with code 0 (0x0).




I don't see you call the download function. Modify your code as follows

        const string RINGCENTRAL_CLIENTID = "0_m0q2SexxxxxxKNQ";
const string RINGCENTRAL_CLIENTSECRET = "S1xxxxxxxxxZMiFFHzzzzzrb_sWSjUg";
const bool RINGCENTRAL_PRODUCTION = false;

const string RINGCENTRAL_USERNAME = "15555555555";
const string RINGCENTRAL_PASSWORD = "Password123!";
const string RINGCENTRAL_EXTENSION = "101";
static RestClient rcsdk;
static void Main(string[] args)
{
// Display the number of command line arguments.
Console.WriteLine(args.Length);
rcsdk = new RestClient(RINGCENTRAL_CLIENTID, RINGCENTRAL_CLIENTSECRET, RINGCENTRAL_PRODUCTION);
rcsdk.Authorize(RINGCENTRAL_USERNAME, RINGCENTRAL_EXTENSION, RINGCENTRAL_PASSWORD).Wait();
download_call_log_callrecording().Wait();
}
static private async Task download_call_log_callrecording()
{
var parameters = new ReadCompanyCallLogParameters();
parameters.dateFrom = "2021-07-05T00:00:00.000Z";
parameters.view = "Simple";
parameters.recordingType = "All";

var path = "recording_content/";
System.IO.Directory.CreateDirectory(path);
long timePerApiCall = 6000;

var resp = await rcsdk.Restapi().Account().CallLog().List(parameters);
foreach (var record in resp.records)
{
Console.WriteLine("-----");
Console.WriteLine("Call recording: " + record.recording.contentUri);
var fileName = path + "call_" + record.recording.id + "_recording";
var start = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
var result = await rcsdk.Restapi().Account().Recording(record.recording.id).Get();
if (result.contentType == "audio/mpeg")
{
fileName += ".mp3";
}
else // can check if "audio/x-wav"
{
fileName += ".wav";
}
var contentUrl = result.contentUri + "?access_token=" + rcsdk.token.access_token;
WebClient webClient = new WebClient();
webClient.DownloadFile(contentUrl, fileName);
Console.WriteLine("Save recording file to the local machine.");
var end = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
var delay = (end - start) * 1000;
Console.WriteLine(delay);
if (delay < timePerApiCall)
{
Thread.Sleep((int)(timePerApiCall - delay));
}
}
}

ok it's working great and for anyone that sees this post here is the full code.


using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using RingCentral;

namespace Recordings
{
class Program
{



const string RINGCENTRAL_CLIENTID = "0_mdddddddddQ";
const string RINGCENTRAL_CLIENTSECRET = "S1h7dddddsWSjUg";
const bool RINGCENTRAL_PRODUCTION = false;

const string RINGCENTRAL_USERNAME = "15555555555";
const string RINGCENTRAL_PASSWORD = "PASSWORD321!";
const string RINGCENTRAL_EXTENSION = "101";

static RestClient rcsdk;
static void Main(string[] args)
{

rcsdk = new RestClient(RINGCENTRAL_CLIENTID, RINGCENTRAL_CLIENTSECRET, RINGCENTRAL_PRODUCTION);
rcsdk.Authorize(RINGCENTRAL_USERNAME, RINGCENTRAL_EXTENSION, RINGCENTRAL_PASSWORD).Wait();
download_call_log_callrecording().Wait();
}
static private async Task download_call_log_callrecording()
{
var parameters = new ReadCompanyCallLogParameters();
parameters.dateFrom = "2021-07-05T00:00:00.000Z";
parameters.view = "Simple";
parameters.recordingType = "All";

//Makes the file path
var path = "c:/recording_content/";
System.IO.Directory.CreateDirectory(path);
long timePerApiCall = 6000;

var resp = await rcsdk.Restapi().Account().CallLog().List(parameters);

foreach (var record in resp.records)
{
Console.WriteLine("-----");
Console.WriteLine("Call recording: " + record.recording.contentUri);
var fileName = path + "call_" + record.recording.id + "_recording";
var start = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
var result = await rcsdk.Restapi().Account().Recording(record.recording.id).Get();
if (result.contentType == "audio/mpeg")
{
fileName += ".mp3";
}
else // can check if "audio/x-wav"
{
fileName += ".wav";
}
var contentUrl = result.contentUri + "?access_token=" + rcsdk.token.access_token;
WebClient webClient = new WebClient();
webClient.DownloadFile(contentUrl, fileName);
Console.WriteLine("Save recording file to the local machine.");
var end = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
var delay = (end - start) * 1000;
Console.WriteLine(delay);
if (delay < timePerApiCall)
{
Thread.Sleep((int)(timePerApiCall - delay));
}
}
}
}
}



so I want to use this in production mode I got the app Active for Production Status. it worked it was downloading all the recordings then it stopped with this error.


System.AggregateException: 'One or more errors occurred. (The remote server returned an error: (429) Too Many Requests.)'

WebException: The remote server returned an error: (429) Too Many Requests.


How can I fix that?


Also, how can I pull the Meta-data from the call log so I have some info on who made the call and the time/day of the call?


How do you handle reading 7000 call logs? Each time you read the call log you will get max 1000 records per page. So with 7000 records, you have yo read 7 times using the next page tokens. You must also take care of the API rate limit (40 calls per 60 secs) of the call log list endpoint. Then when you download the recordings, the rate limit is 10 downloads per 60 secs. Read this article to learn more about API rate limit and how to handle it.

You do need to handle exception and check each call recording record.recording.contentUri is not null.

All in all, my snippet code is a sample and you need to fine tune it for your production code.


Reply