Voximplant. Blog

Step-by-step call center tutorial part 5

Waiting in a queue

Having a full control over an incoming and outgoing calls allows to implement any business needs. By default, a user will hear nothing while waiting in the queue, since we have not instructed VoxEngine to produce any audio. Good practice is to inform the user about his or her queue position and play some music to indicate the call in progress.

Let’s start by adding the background music by using the call object’s startPlayback method. In order to start background music, add the following source code:

  1. inc.addEventListener(CallEvents.Connected, function() {
  2. var isLoop = true;
  3. inc.startPlayback("http://cdn.voximplant.com/bb_remix.mp3", isLoop);
  4. request = VoxEngine.enqueueACDRequest("main", incId);

Important note: outside of conference rooms, any call object can have only one audio source. So if you are using startPlayback and then say, the say method call will detach startPlayback audio and attach it’s own audio. After say finishes, audio from startPlayback will not be automatically attached back. Music automatically stops after operator answers and new audio source is connected to call via sendMediaBetween.

One more thing to do is queue position notification. This is done by periodically calling a getStatus method of the queue request object and subscribing to the the ACDEvents.Waiting event. The event receives queue position info as position and ewt (estimated wait time) properties of an event handler parameter:

  1. // This event only fired if request was queued without errors.
  2. request.addEventListener(ACDEvents.Queued, function(e) {
  3. request.getStatus();
  4. });
  5. request.addEventListener(ACDEvents.Waiting, function(e) {
  6. inc.say("Queue position is " + e.position);
  7. inc.addEventListener(CallEvents.PlaybackFinished, function(e) {
  8. // Note that say() changes audio source, so we need to change it back,
  9. // but only if operator is not yet connected.
  10. if (!out) {
  11. inc.startPlayback("http://cdn.voximplant.com/bb_remix.mp3", isLoop);
  12. }
  13. });
  14. setTimeout(function() { request.getStatus(); }, 30000);
  15. });

While that setup will work in most situations, where are so-called “edge cases” what can be gracefully handled. For example, if no operators are connected, it’s definitely not possible to queue a request. For such “error cases” ACD module fires a number of events:

It will be a good idea to handle such events and provide the caller with a meaningful way to reach an operator, like asking a permission for callback and passing phone number to your backend, so an operator can call back manually or automatically later.

Complete source code for this step:

  1. require(Modules.ACD);
  3. VoxEngine.addEventListener(AppEvents.CallAlerting, function(e) {
  4. var inc = e.call;
  5. var incId = e.callerid;
  6. var request = null;
  7. var out = null;
  8. inc.answer();
  9. inc.addEventListener(CallEvents.Connected, function() {
  10. var isLoop = true;
  11. inc.startPlayback("http://cdn.voximplant.com/bb_remix.mp3", isLoop);
  12. request = VoxEngine.enqueueACDRequest("main", incId);
  13. // This event only fired if request was queued without errors.
  14. request.addEventListener(ACDEvents.Queued, function(e) {
  15. request.getStatus();
  16. });
  17. request.addEventListener(ACDEvents.Waiting, function(e) {
  18. inc.say("Queue position is " + e.position);
  19. inc.addEventListener(CallEvents.PlaybackFinished, function(e) {
  20. // Note that say() changes audio source, so we need to change it back,
  21. // but only if operator is not yet connected.
  22. if (!out) {
  23. inc.startPlayback("http://cdn.voximplant.com/bb_remix.mp3", isLoop);
  24. }
  25. });
  26. setTimeout(function() { request.getStatus(); }, 30000);
  27. });
  28. request.addEventListener(ACDEvents.OperatorReached, function (e) {
  29. out = e.operatorCall;
  30. VoxEngine.sendMediaBetween(inc, out);
  31. out.addEventListener(CallEvents.Disconnected, function() {
  32. inc.hangup();
  33. // Some logic can be performed instead of session termination
  34. VoxEngine.terminate();
  35. });
  36. });
  37. });
  38. inc.addEventListener(CallEvents.Disconnected, function() {
  39. // If operator already connected, this also hangs up operator's call.
  40. // Also cancels all events like ACDEvents.Waiting
  41. request.cancel();
  42. // Some logic can be performed instead of session termination
  43. VoxEngine.terminate();
  44. });
  45. });

Tagged in