I am currently constructing a C#.NET wrapper for the Asterisk Interface Manager.
I can do simple things like transfers and hangups. I am now in the process of building conference calling. I can set up an n-user conference, but I have to do so in terms of "Action: redirect" on existing active channels.
What I'd like to do is route as now non-existent calls (i.e. there is no channel in "core show channels") to my context/extension that puts people in conference rooms.
But I cannot get "Action: originate" to work for anything. What does originate take a channel as an argument when there is not channel yet? What is it that you pass to the channel header? SIP/ does not work for me.
Thanks in advance.
What exactly are you trying to do? You can't use a non-existent channel to bridge into a conference room. If you're looking to create a conference, then have people called on their extensions (or on any number, really) and placed into the conference room, that's simple.
I assume you're using Asterisk.NET. The originate command expects a number to dial (this is the channel), a context, and an extension to connect the call to within the dialplan (this can be hard-coded or can presumably be created through the AMI).
Say you set up a conference room on extension 300. Your originate command would look something like this:
OriginateAction oc = new OriginateAction();
oc.Context = "YourDialPlanContext";
oc.Priority = 1;
// Channel is however you're dialing (extensions, SIP, DAHDI, etc.)
oc.Channel = "SIP/12125551212#Your-Sip-Prover-Peer-Name";
// or in the alternative
// oc.Channel = "ZAP/ZapChannelName/12125551212";
oc.CallerId = "9998887777";
// This is the extension you want dialed once the call is connected
// 300 in our example
oc.Exten = "300";
oc.Timeout = 60000; // Our timeout in ms
oc.Variable = "VAR1=ABC|VAR2=25"; // If you need to pass variables to the dialplan
// Async should be set to true, unless you want your code to wait until the call
// is complete
oc.Async = true;
// Go ahead and place the call
ManagerResponse originateResponse = AsteriskManager.SendAction(oc, oc.Timeout);
Voila! You have now originated a call to your intended conference participant, and upon answering they will be directed into your conference room.
Related
I have integrated Pay with Amazon with my web app, but I have determined that capturing funds only works when I step through the code debugging, and does not happen if I don't have a break-point. To me, this indicates that a pause is necessary. I am using recurring payments. The relevant section of code is below:
...
//make checkout object
AmazonAutomaticSimpleCheckout asc = new AmazonAutomaticSimpleCheckout(billingAgreeementId);
//capture
CaptureResponse cr = asc.Capture(authId, amount, 1);
//check if capture was successful
if (cr.CaptureResult.CaptureDetails.CaptureStatus.State == PaymentStatus.COMPLETED)
{
...
//give the user the things they paid for in the database
...
return "success";
}
...
So, if I have a break-point at the capture line under //capture, then the function returns success. If I do not have the break-point, I get a runtime exception System.NullReferenceException: Object reference not set to an instance of an object. regarding the following if statement.
To me, this implies that I should be able to await the capture method.
Also note, the capture(...) method is calling the CaptureAction(...) method, just as the C# sample does.
//Invoke the Capture method
public CaptureResponse Capture(string authId, string captureAmount, int indicator)
{
return CaptureAction(propertiesCollection, service, authId, captureAmount, billingAgreementId, indicator, null, null);
}
How can I await the capture call? Am I forgetting to pass a parameter to indicate that it should execute the operation immediately?
It seems after some experimentation, that a function that will essentially achieve the wait I was performing manually using a break-point is the function CheckAuthorizationStatus(), which is also in the C# sample provided with the documentation.
So the fixed code simply adds CheckAuthorizationStatus() before calling the capture() method. CheckAuthorizationStatus() apparently loops until the state of the authorization changes. This seems somewhat kludgey to me, but seems to be how the Pay with Amazon APIs are meant to be used, as best I can tell. Corrected code below:
//make checkout object
AmazonAutomaticSimpleCheckout asc = new AmazonAutomaticSimpleCheckout(billingAgreeementId);
//capture
CaptureResponse cr;
GetAuthorizationDetailsResponse gadr = asc.CheckAuthorizationStatus(authId);
cr = asc.Capture(authId, amount, 1);
//gadr = asc.CheckAuthorizationStatus(authId);
//check if capture was succeddful
if (cr.CaptureResult.CaptureDetails.CaptureStatus.State == PaymentStatus.COMPLETED)
{
...
return "success";
}
When using asynchronous mode you will typically rely on a couple of ways of handling it. The result of AuthorizeOnBillingAgreement will return a Amazon authorization Id (e.g. P01-1234567-1234567-A000001). Once you have the authorization Id you can:
Poll GetAuthorizationDetails - This will return the authorization details which will contain the "State" of the authorization. When the state is "Open" you can then make the Capture API call passing in the authorization Id.
Wait for the Instant Payment Notification (IPN). If you have a IPN handler you can watch for it and make the capture API call as described in step 1. The IPN is usually sent within 60 seconds and it will have the final processing status (Open or Declined).
You shouldn't add an arbitrary pause. You should always check the state of the authorization before making the capture. Even if the payment status is completed you still need to check the state.
Disclaimer:
I don't implement recurring payments, only a straightforward payment - though just reading the documentation it seems similar or at least there is a synchronous option.
Because it meets my requirements, I opt for the synchronous process. In essence treating it like a "payment gateway" - give me the result "now" and I'll deal with whatever result.
Additionally, AUTH and CAPTURE in one step - again, this is based on one's operational requirement/s.
The 2 related items are:
CaptureNow=true
TransactionTimeout=0
A value of zero always returns a synchronous Open or Declined
You'll get (synchronously):
AuthorizeResult.AuthorizationDetails which will have
AmazonAuthorizationId, AuthorizationAmount, etc
AuthorizeResult.AuthorizationDetails.IdList
null on failure
otherwise it will contain the capture id (if capture was successful)
AuthorizeResult.AuthorizationDetails.IdList.member - I've only seen this to contain 1 item (the CaptureId)
You can then use the CaptureId to call GetCaptureDetails and do what you need to do after parsing the GetCaptureDetailsResponse
Again, above is based on Payments API flow (not recurring Payments/Billing Agreement) so I hope it at least helps/gives you an avenue/idea for testing the synchronous option.
I'm trying to create a project where I use the ohLibspotify .Net libspotify wrapper to login to spotify and stream playlists.
As far as I can see I've set everything up the same way like in the example. First create a session like so:
SpotifySessionConfig sp_config = new SpotifySessionConfig()
{
ApiVersion = 12,
CacheLocation = "cache",
SettingsLocation = "settings",
UserAgent = "player",
ApplicationKey = Properties.Resources.appkey,
Listener = new sp_Listener()
};
sp_session = SpotifySession.Create(sp_config);
Then I call relogin() if that fails than I show the login window to the user because no stored credentials have been found. When the user has supplied me with his account details I call login(username, password, true, null). After that I'm awaiting a call back to the sp_Listener class.
In the sp_Listener class I have overridden the following functions:
SpotifySessionListener.LoggedIn(SpotifySession session, SpotifyError error)
SpotifySessionListener.ConnectionError(SpotifySession session, SpotifyError error)
SpotifySessionListener.LogMessage(SpotifySession session, string data)
The only callback that gets called is the LogMessage callback. I've hooked it up to log4net to read all the output efficiently. This is all of the LogMessageoutput:
2015-02-22 20:58:38,636 [18] DEBUG Namespace.sp_Listener - 19:58:38.634 I [c:/Users/spotify-buildagent/BuildAgent/work/1e0ce8a77adfb2dc/client/core/session/offline_authorizer.cpp:297] Unable to login offline: no such user
2015-02-22 20:58:38,649 [18] DEBUG Namespace.sp_Listener - 19:58:38.649 I [c:/Users/spotify-buildagent/BuildAgent/work/1e0ce8a77adfb2dc/client/core/session/offline_authorizer.cpp:297] Unable to login offline: no such user
2015-02-22 20:58:38,651 [14] DEBUG Namespace.sp_Listener - 19:58:38.649 E [c:/Users/spotify-buildagent/BuildAgent/work/1e0ce8a77adfb2dc/client/core/network/proxy_resolver_win32.cpp:215] WinHttpGetProxyForUrl failed
2015-02-22 20:58:38,664 [19] DEBUG Namespace.sp_Listener - 19:58:38.661 I [ap:1752] Connecting to AP ap.gslb.spotify.com:4070
2015-02-22 20:58:38,713 [19] DEBUG Namespace.sp_Listener - 19:58:38.713 I [ap:1226] Connected to AP: 193.182.7.34:4070
It seems like I must have forgotten something. I've no idea what, maybe one of you guys knows a solution.
I'm the original author of the ohLibSpotify wrapper library. I think you possibly have overlooked the need to call ProcessEvents. ohLibSpotify tries as far as possible to provide only a thin layer over libspotify. Almost everything in the libspotify docs remains relevant when you are using ohLibSpotify, and you should consider those docs your first port-of-call. https://developer.spotify.com/docs/libspotify/12.1.51/index.html
In particular:
The library itself uses multiple threads internally. To allow for synchronization between these threads, you must implement the sp_session_callbacks::notify_main_thread callback. Whenever called (from some internal thread), the application must wake up the main loop so the sp_session_process_events() function can be run.
The API itself is not thread-safe. Thus, you must take care not to call the API functions from more than one of your own threads.
The names are slightly different, but the concepts are the same - you need to implement NotifyMainThread to get notifications that libspotify wants to communicate with you, then you need to make sure that your main thread calls sp_session.ProcessEvents. You also need to make sure that only one thread ever interacts with ohLibSpotify at a time, either by coordinating so that only one thread calls ohLibSpotify, or by using appropriate locks around calls into ohLibSpotify.
(I'm using libspotify names here: the following advice applies equally whether you're using libspotify directory or ohLibSpotify.)
With a few exceptions, libspotify only ever calls your callbacks from inside a call to sp_session_process_events. (The exceptions are notify_main_thread and the callbacks associated with music delivery.) So if you're not set up to call that regularly, you'll find that libspotify doesn't do very much. If your program has an event loop, you should arrange to send yourself events whenever you receive the notify_main_thread callback or when the time specified by your last call to sp_session_process_events has passed, and call sp_session_process_events in the event handler. If you have no event loop, you might want to spawn a thread for this purpose, and make sure to use appropriate locks to stop other threads from calling into libspotify at the same time.
I want to hold/unhold my calls using Asterisk AMI. I have used Park AMI Action. Then, My phone disconnects, and Senders phone plays a music. How to Unpark this Call ? Can anybody help me Please ?
UnParkAction upac = new UnParkAction(channel, channel1, "360000");
ManagerResponse rr = ApplicationVariables.manager.SendAction(upac); //Sending it to Manager COnnection
You can use Redirect AMI command.
This solves the unparking issue but with a difference that the initiator will still need to answer a call. In other words he does not fully retrieve the call without any action at all.
In more detail:
When you park the call you need to have both channels:
(1) Channel to be parked
(2) Channel that makes the park
Store in a static variable (1).
Then when you finished parking do the following:
Initiate redirect call from the Channel parked (essentially what you have stored) and as destination, your number.
Example URL:
https://<YOUR AMI URL>?action=Redirect&channel=" + channelParked + "&context=" + context + "&priority=1&Exten=" + myPhoneNumber;
When you parking call it say you parking lot id.
You have call that lot id to catch phone.
If you want just hold it use Musiconhold command.
If you want more controlable automated parking-like setup, use transfer to conference on musiconhold extension.
I am working on an assignment in asp.net to send notification email to users at specific intervals.
But the problem is that since the server is not privately owned i cannot implement a windows service on it.
Any ideas?
There's no reliable way to achieve that. If you cannot install a Windows Service on the host you could write a endpoint (.aspx or .ashx) that will send the email and then purchase on some other site a service which will ping this endpoint at regular intervals by sending it HTTP request. Obviously you should configure this endpoint to be accessible only from the IP address of the provider you purchase the service from, otherwise anyone could send an HTTP request to the endpoint and trigger the process which is probably undesirable.
Further reading: The Dangers of Implementing Recurring Background Tasks In ASP.NET.
There are several ways to get code executing on an interval that don't require a windows service.
One option is to use the Cache class - use one of the Insert overloads that takes a CacheItemRemovedCallback - this will be called when the cache item is removed. You can re-add the cache item with this callback again and again...
Though, the first thing you need to do is contact the hosting company and find out if they already have some sort of solution for you.
You could set up a scheduled task on the server to invoke a program with the desired action.
You can always use a System.Timer and create a call at specific intervals. What you need to be careful is that this must be run one time, eg on application start, but if you have more than one pools, then it may run more times, and you also need to access some database to read the data of your actions.
using System.Timers;
var oTimer = new Timer();
oTimer.Interval = 30000; // 30 second
oTimer.Elapsed += new ElapsedEventHandler(MyThreadFun);
oTimer.Start();
private static void MyThreadFun(object sender, ElapsedEventArgs e)
{
// inside here you read your query from the database
// get the next email that must be send,
// you send them, and mark them as send, log the errors and done.
}
why I select system timer:
http://msdn.microsoft.com/en-us/magazine/cc164015.aspx
more words
I use this in a more complex class and its work fine. What are the points that I have also made.
Signaling the application stop, to wait for the timer to end.
Use mutex and database for synchronize the works.
Easiest solution is to exploit global.asax application events
On application startup event, create a thread (or task) into a static singleton variable in the global class.
The thread/task/workitem will have an endless loop while(true) {...} with your "service like" code inside.
You'll also want to put a Thread.Sleep(60000) in the loop so it doesn't eat unnecessary CPU cycles.
static void FakeService(object obj) {
while(true) {
try {
// - get a list of users to send emails to
// - check the current time and compare it to the interval to send a new email
// - send emails
// - update the last_email_sent time for the users
} catch (Exception ex) {
// - log any exceptions
// - choose to keep the loop (fake service) running or end it (return)
}
Thread.Sleep(60000); //run the code in this loop every ~60 seconds
}
}
EDIT Because your task is more or less a simple timer job any of the ACID type concerns from an app pool reset or other error don't really apply, because it can just start up again and keep trucking along with any data corruption. But you could also use the thread to simply execute a request to an aspx or ashx that would hold your logic.
new WebClient().DownloadString("http://localhost/EmailJob.aspx");
How can I integrate Lync 2010, with a program that does a DB look up and shows a small popup, with the information found, and also a few buttons with some options.
The program is already running with some other types of phone systems, I kind of need a connector for Lync.
I don't want to put a tab or other UI inside Lync.
You'll need to start with the Lync SDK. You can build your app as a Winforms or WPF app.
Signing In
To connect and sign in to the running instance of Lync, check out this page from the SDK. Make sure you keep a reference to the LyncClient object that represents Lync. This can be got by calling the static method LyncClient.GetClient()
Detecting an incoming call
To detect an incoming call, you can listen for the ConversationManager.ConversationAdded event. ConversationManager is a property on your LyncClient instance.
To determine if the call is a) an Audio call, and b) incoming (as opposed to an outgoing call placed by the user) you can use the following method:
bool IsIncomingAVCall(Conversation conversation)
{
// Test to see if the call contains the AV modality
bool containsAVModality = conversation.Modalities.ContainsKey(ModalityTypes.AudioVideo);
if (containsAVModality)
{
// Get the state of the AV modality
var state = conversation.Modalities[ModalityTypes.AudioVideo].State;
// 'Notified' means the call is incoming
if (state == ModalityState.Notified) return true;
}
return false;
}
In the ConversationAdded event, you should sign up to the Conversation.ParticipantAdded event, so you can check who the caller is. The EventArgs object has a Participant property, which in turn has a Contact property. The Contact property has a number of properties including Uri, which should give you the phone number (if that's what you need).
You can then make your DB call and pop your info.
Edit: I've written a blog post about screen pops which goes into much more detail - here
Placing a call
If your app is WPF, the easiest way to allow a call to be placed is by using the StartAudioCallButton control. Otherwise, the instructions here should help.