Apologies for our API Explorer being out of sync with the API Developer Guide (which is more comprehensive, official, and shows the response body as empty on a DELETE to the route you provided).
https://developers.ringcentral.com/api-docs/latest/index.html#!#RefRingOut.htmlI will take a look at the RingOut and canceling a RingOut and if I am able to recreate your experience will create an issue with our engineering team to inspect/resolve appropriately.
If I am unable to recreate, I may have some additional inquiries.
Thanks for providing the headers and request/response information.
I've seen a thread of email going on about this inquiry, before I provide any more information on this, I have a question:
1. I see the state of the call is "InProgress", but when you initiate the DELETE request, is that being done before/during/after any leg of the call has been connected, and if yes, at which leg and what is the state (if observing the presence notifications) please?
The reason I ask is because currently, if the state of the call switches to "Ringing" that is considered as connected according to our current implementation and cannot be canceled. It seems this might need some improvement, but I'm trying to gather as much information as possible.
I am trying to hangup the call. This might happen at any point in the calling process.
From your previous comment, it seems that I misunderstood the purpose of this method. If DELETE only works to stop a call before it has been answered, how do we hangup a call once it is answered?
The person on the call would be required to hangup the call, AFAIK that is the only way, but I will ask around.
A long time ago I wrote a dialer that did not automatically disconnect a zombie call and a call was placed to Afghanistan for several days. The bill was in the thousands. Also, for totally hands free calling within an application, we would like to automatically hangup when the last page is entered.
Are you willing/able to share the code you wrote for that Dave?
public String StopCall(Terminal _t) {
String sBody = String.Empty;
byte[] byteBody = null;
try
{
byteBody = new byte[2] { 123, 125 };
SendReceive("DELETE", "/restapi/v1.0/account/~/extension/~/ringout/" + _t.CallId, "Bearer", _t.Access_Token, byteBody);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return String.Empty;
}
private void SendReceive(String method, String uri, String tokenType, String authcode, byte[] byteBody)
{
Stream sResponse = null;
Stream sRequest = null;
StreamReader srResponse = null;
HttpWebResponse HttpWResp = null;
String sBody = String.Empty;
ASCIIEncoding encoding = new ASCIIEncoding();
HttpWebRequest HttpWReq = null;
try
{
HttpWReq = (HttpWebRequest)WebRequest.Create(baseURL + uri);
HttpWReq.Method = method;
HttpWReq.KeepAlive = true;
if (tokenType.Trim().Length > 0 && authcode.Trim().Length > 0)
{
HttpWReq.UserAgent = appName + "/" + appVersion;
HttpWReq.Headers[HttpRequestHeader.Authorization] = string.Format("{0} {1}", tokenType.Trim(), authcode.Trim());
}
if (HttpWReq.Method == "POST")
{
if (HttpWReq.RequestUri.ToString().Contains("oauth/"))
{
HttpWReq.ContentType = "application/x-www-form-urlencoded;charset=UTF-8";
}
else
{
HttpWReq.ContentType = "application/json";
}
HttpWReq.ContentLength = byteBody.Length;
//Add parameters to the Body - Go figure
//Task<sRequest>HttpWReq.GetRequestStreamAsync();
sRequest = HttpWReq.GetRequestStream();
sRequest.Write(byteBody, 0, byteBody.Length);
//Console.WriteLine(sBody);
}
if (HttpWReq.Method == "DELETE")
{
HttpWReq.Accept = "application/json";
HttpWReq.ContentType = "application/json; charset=UTF-8";
HttpWReq.Headers.Add("X-HTTP-Method-Override", "DELETE");
}
//Send Request and Get the Response
HttpWResp = (HttpWebResponse)HttpWReq.GetResponse();
switch (HttpWResp.StatusCode.ToString())
{
case "OK": //== HttpStatusCode.OK)
sResponse = HttpWResp.GetResponseStream();
srResponse = new StreamReader(sResponse);
String s = srResponse.ReadToEnd();
jt = JToken.Parse(s);
break;
case "NoContent":// Output from DELETE
break;
default:
break;
}
}
catch (Exception ex)
{
Console.WriteLine(String.Format("{0} {1}", ex.Message, ex.GetType().FullName));
}
finally
{
if (HttpWResp != null)
{
HttpWResp.Close();
}
else
{
HttpWReq.Abort();
}
}
}
Probably the only thing that needs explanation is the Terminal Class. This is an object that is instantiated for each extension and holds the relevant data like the CallId and the auth token
Awesome! Thanks for sharing Dave!