1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.asteriskjava.live.internal;
18
19 import org.asteriskjava.live.*;
20 import org.asteriskjava.manager.ResponseEvents;
21 import org.asteriskjava.manager.action.StatusAction;
22 import org.asteriskjava.manager.event.*;
23 import org.asteriskjava.util.DateUtil;
24 import org.asteriskjava.util.Log;
25 import org.asteriskjava.util.LogFactory;
26
27 import java.util.*;
28
29
30
31
32
33
34
35 class ChannelManager
36 {
37 private final Log logger = LogFactory.getLog(getClass());
38
39
40
41
42 private static final long REMOVAL_THRESHOLD = 15 * 60 * 1000L;
43 private static final long SLEEP_TIME_BEFORE_GET_VAR = 50L;
44
45 private final AsteriskServerImpl server;
46
47
48
49
50 private final Set<AsteriskChannelImpl> channels;
51
52
53
54
55
56
57 ChannelManager(AsteriskServerImpl server)
58 {
59 this.server = server;
60 this.channels = new HashSet<AsteriskChannelImpl>();
61 }
62
63 void initialize() throws ManagerCommunicationException
64 {
65 initialize(null);
66 }
67
68 void initialize(List<String> variables) throws ManagerCommunicationException
69 {
70 ResponseEvents re;
71
72 disconnected();
73 StatusAction sa = new StatusAction();
74 sa.setVariables(variables);
75 re = server.sendEventGeneratingAction(sa);
76 for (ManagerEvent event : re.getEvents())
77 {
78 if (event instanceof StatusEvent)
79 {
80 handleStatusEvent((StatusEvent) event);
81 }
82 }
83 }
84
85 void disconnected()
86 {
87 synchronized (channels)
88 {
89 channels.clear();
90 }
91 }
92
93
94
95
96
97
98 Collection<AsteriskChannel> getChannels()
99 {
100 Collection<AsteriskChannel> copy;
101
102 synchronized (channels)
103 {
104 copy = new ArrayList<AsteriskChannel>(channels.size() + 2);
105 for (AsteriskChannel channel : channels)
106 {
107 if (channel.getState() != ChannelState.HUNGUP)
108 {
109 copy.add(channel);
110 }
111 }
112 }
113 return copy;
114 }
115
116 private void addChannel(AsteriskChannelImpl channel)
117 {
118 synchronized (channels)
119 {
120 channels.add(channel);
121 }
122 }
123
124
125
126
127 private void removeOldChannels()
128 {
129 Iterator<AsteriskChannelImpl> i;
130
131 synchronized (channels)
132 {
133 i = channels.iterator();
134 while (i.hasNext())
135 {
136 final AsteriskChannel channel = i.next();
137 final Date dateOfRemoval = channel.getDateOfRemoval();
138 if (channel.getState() == ChannelState.HUNGUP && dateOfRemoval != null)
139 {
140 final long diff = DateUtil.getDate().getTime() - dateOfRemoval.getTime();
141 if (diff >= REMOVAL_THRESHOLD)
142 {
143 i.remove();
144 }
145 }
146 }
147 }
148 }
149
150 private AsteriskChannelImpl addNewChannel(String uniqueId, String name,
151 Date dateOfCreation, String callerIdNumber, String callerIdName,
152 ChannelState state, String account)
153 {
154 final AsteriskChannelImpl channel;
155 final String traceId;
156
157 channel = new AsteriskChannelImpl(server, name, uniqueId, dateOfCreation);
158 channel.setCallerId(new CallerId(callerIdName, callerIdNumber));
159 channel.setAccount(account);
160 channel.stateChanged(dateOfCreation, state);
161 logger.info("Adding channel " + channel.getName() + "(" + channel.getId() + ")");
162
163 if (SLEEP_TIME_BEFORE_GET_VAR > 0)
164 {
165 try
166 {
167 Thread.sleep(SLEEP_TIME_BEFORE_GET_VAR);
168 }
169 catch (InterruptedException e)
170 {
171 Thread.currentThread().interrupt();
172 }
173 }
174
175 traceId = getTraceId(channel);
176 channel.setTraceId(traceId);
177
178 addChannel(channel);
179
180 if (traceId != null && (!name.toLowerCase(Locale.ENGLISH).startsWith("local/") || (name.endsWith(",1") || name.endsWith(";1"))))
181 {
182 final OriginateCallbackData callbackData;
183 callbackData = server.getOriginateCallbackDataByTraceId(traceId);
184 if (callbackData != null && callbackData.getChannel() == null)
185 {
186 callbackData.setChannel(channel);
187 try
188 {
189 callbackData.getCallback().onDialing(channel);
190 }
191 catch (Throwable t)
192 {
193 logger.warn("Exception dispatching originate progress.", t);
194 }
195 }
196 }
197 server.fireNewAsteriskChannel(channel);
198 return channel;
199 }
200
201 void handleStatusEvent(StatusEvent event)
202 {
203 AsteriskChannelImpl channel;
204 final Extension extension;
205 boolean isNew = false;
206 Map<String, String> variables = event.getVariables();
207
208 channel = getChannelImplById(event.getUniqueId());
209 if (channel == null)
210 {
211 Date dateOfCreation;
212
213 if (event.getSeconds() != null)
214 {
215 dateOfCreation = new Date(DateUtil.getDate().getTime() - (event.getSeconds() * 1000L));
216 }
217 else
218 {
219 dateOfCreation = DateUtil.getDate();
220 }
221 channel = new AsteriskChannelImpl(server, event.getChannel(), event.getUniqueId(), dateOfCreation);
222 isNew = true;
223 if (variables != null)
224 {
225 for (String variable : variables.keySet())
226 {
227 channel.updateVariable(variable, variables.get(variable));
228 }
229 }
230 }
231
232 if (event.getContext() == null && event.getExtension() == null
233 && event.getPriority() == null)
234 {
235 extension = null;
236 }
237 else
238 {
239 extension = new Extension(event.getContext(), event.getExtension(), event.getPriority());
240 }
241
242 synchronized (channel)
243 {
244 channel.setCallerId(new CallerId(event.getCallerIdName(), event.getCallerIdNum()));
245 channel.setAccount(event.getAccountCode());
246 if (event.getChannelState() != null)
247 {
248 channel.stateChanged(event.getDateReceived(), ChannelState.valueOf(event.getChannelState()));
249 }
250 channel.extensionVisited(event.getDateReceived(), extension);
251
252 if (event.getBridgedChannel() != null)
253 {
254 final AsteriskChannelImpl linkedChannel = getChannelImplByName(event.getBridgedChannel());
255 if (linkedChannel != null)
256 {
257
258 channel.channelLinked(event.getDateReceived(), linkedChannel);
259 synchronized (linkedChannel)
260 {
261 linkedChannel.channelLinked(event.getDateReceived(), channel);
262 }
263 }
264 }
265 }
266
267 if (isNew)
268 {
269 logger.info("Adding new channel " + channel.getName());
270 addChannel(channel);
271 server.fireNewAsteriskChannel(channel);
272 }
273 }
274
275
276
277
278
279
280
281
282
283 AsteriskChannelImpl getChannelImplByName(String name)
284 {
285 Date dateOfCreation = null;
286 AsteriskChannelImpl channel = null;
287
288 if (name == null)
289 {
290 return null;
291 }
292
293 synchronized (channels)
294 {
295 for (AsteriskChannelImpl tmp : channels)
296 {
297 if (tmp.getName() != null && tmp.getName().equals(name))
298 {
299
300 if (dateOfCreation == null ||
301 tmp.getDateOfCreation().after(dateOfCreation) ||
302 (tmp.getDateOfCreation().equals(dateOfCreation) && tmp.getState() != ChannelState.HUNGUP))
303 {
304 channel = tmp;
305 dateOfCreation = channel.getDateOfCreation();
306 }
307 }
308 }
309 }
310 return channel;
311 }
312
313
314
315
316
317
318
319 AsteriskChannelImpl getChannelImplByNameAndActive(String name)
320 {
321
322
323
324
325
326
327
328 AsteriskChannelImpl channel = null;
329
330 if (name == null)
331 {
332 return null;
333 }
334
335 synchronized (channels)
336 {
337 for (AsteriskChannelImpl tmp : channels)
338 {
339 if (tmp.getName() != null && tmp.getName().equals(name) && tmp.getState() != ChannelState.HUNGUP)
340 {
341 channel = tmp;
342 }
343 }
344 }
345 return channel;
346 }
347
348 AsteriskChannelImpl getChannelImplById(String id)
349 {
350 if (id == null)
351 {
352 return null;
353 }
354
355 synchronized (channels)
356 {
357 for (AsteriskChannelImpl channel : channels)
358 {
359 if (id.equals(channel.getId()))
360 {
361 return channel;
362 }
363 }
364 }
365 return null;
366 }
367
368
369
370
371
372
373
374
375
376
377
378
379
380 AsteriskChannelImpl getOtherSideOfLocalChannel(AsteriskChannel localChannel)
381 {
382 final String name;
383 final char num;
384
385 if (localChannel == null)
386 {
387 return null;
388 }
389
390 name = localChannel.getName();
391 if (name == null || !name.startsWith("Local/") || (name.charAt(name.length() - 2) != ',' && name.charAt(name.length() - 2) != ';'))
392 {
393 return null;
394 }
395
396 num = name.charAt(name.length() - 1);
397
398 if (num == '1')
399 {
400 return getChannelImplByName(name.substring(0, name.length() - 1) + "2");
401 }
402 else if (num == '2')
403 {
404 return getChannelImplByName(name.substring(0, name.length() - 1) + "1");
405 }
406 else
407 {
408 return null;
409 }
410 }
411
412 void handleNewChannelEvent(NewChannelEvent event)
413 {
414 final AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
415
416 if (channel == null)
417 {
418 if (event.getChannel() == null)
419 {
420 logger.info("Ignored NewChannelEvent with empty channel name (uniqueId=" + event.getUniqueId() + ")");
421 }
422 else
423 {
424 addNewChannel(
425 event.getUniqueId(), event.getChannel(), event.getDateReceived(),
426 event.getCallerIdNum(), event.getCallerIdName(),
427 ChannelState.valueOf(event.getChannelState()), event.getAccountCode());
428 }
429 }
430 else
431 {
432
433 synchronized (channel)
434 {
435 channel.nameChanged(event.getDateReceived(), event.getChannel());
436 channel.setCallerId(new CallerId(event.getCallerIdName(), event.getCallerIdNum()));
437 channel.stateChanged(event.getDateReceived(), ChannelState.valueOf(event.getChannelState()));
438 }
439 }
440 }
441
442 void handleNewExtenEvent(NewExtenEvent event)
443 {
444 AsteriskChannelImpl channel;
445 final Extension extension;
446
447 channel = getChannelImplById(event.getUniqueId());
448 if (channel == null)
449 {
450 logger.error("Ignored NewExtenEvent for unknown channel " + event.getChannel());
451 return;
452 }
453
454 extension = new Extension(
455 event.getContext(), event.getExtension(), event.getPriority(),
456 event.getApplication(), event.getAppData());
457
458 synchronized (channel)
459 {
460 channel.extensionVisited(event.getDateReceived(), extension);
461 }
462 }
463
464 void handleNewStateEvent(NewStateEvent event)
465 {
466 AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
467
468 if (channel == null)
469 {
470
471 channel = getChannelImplByNameAndActive(event.getChannel());
472 if (channel != null)
473 {
474 logger.info("Changing unique id for '" + channel.getName() + "' from " + channel.getId() + " to " + event.getUniqueId());
475 channel.idChanged(event.getDateReceived(), event.getUniqueId());
476 }
477
478 if (channel == null)
479 {
480 logger.info("Creating new channel due to NewStateEvent '" + event.getChannel() + "' unique id " + event.getUniqueId());
481
482 channel = addNewChannel(
483 event.getUniqueId(), event.getChannel(), event.getDateReceived(),
484 event.getCallerIdNum(), event.getCallerIdName(),
485 ChannelState.valueOf(event.getChannelState()), null
486 }
487 }
488
489
490
491 if (event.getCallerIdNum() != null || event.getCallerIdName() != null)
492 {
493 String cidnum = "";
494 String cidname = "";
495 CallerId currentCallerId = channel.getCallerId();
496
497 if (currentCallerId != null)
498 {
499 cidnum = currentCallerId.getNumber();
500 cidname = currentCallerId.getName();
501 }
502
503 if (event.getCallerIdNum() != null)
504 {
505 cidnum = event.getCallerIdNum();
506 }
507
508 if (event.getCallerIdName() != null)
509 {
510 cidname = event.getCallerIdName();
511 }
512
513 CallerId newCallerId = new CallerId(cidname, cidnum);
514 logger.debug("Updating CallerId (following NewStateEvent) to: " + newCallerId.toString());
515 channel.setCallerId(newCallerId);
516
517
518
519
520 if (event.getChannel() != null && !event.getChannel().equals(channel.getName()))
521 {
522 logger.info("Renaming channel (following NewStateEvent) '" + channel.getName() + "' to '" + event.getChannel() + "'");
523 synchronized (channel)
524 {
525 channel.nameChanged(event.getDateReceived(), event.getChannel());
526 }
527 }
528 }
529
530 if (event.getChannelState() != null)
531 {
532 synchronized (channel)
533 {
534 channel.stateChanged(event.getDateReceived(), ChannelState.valueOf(event.getChannelState()));
535 }
536 }
537 }
538
539 void handleNewCallerIdEvent(NewCallerIdEvent event)
540 {
541 AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
542
543 if (channel == null)
544 {
545
546 channel = getChannelImplByNameAndActive(event.getChannel());
547 if (channel != null)
548 {
549 logger.info("Changing unique id for '" + channel.getName() + "' from " + channel.getId() + " to " + event.getUniqueId());
550 channel.idChanged(event.getDateReceived(), event.getUniqueId());
551 }
552
553 if (channel == null)
554 {
555
556 channel = addNewChannel(
557 event.getUniqueId(), event.getChannel(), event.getDateReceived(),
558 event.getCallerIdNum(), event.getCallerIdName(),
559 ChannelState.DOWN, null
560 }
561 }
562
563 synchronized (channel)
564 {
565 channel.setCallerId(new CallerId(event.getCallerIdName(), event.getCallerIdNum()));
566 }
567 }
568
569 void handleHangupEvent(HangupEvent event)
570 {
571 HangupCause cause = null;
572 AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
573
574 if (channel == null)
575 {
576 logger.error("Ignored HangupEvent for unknown channel " + event.getChannel());
577 return;
578 }
579
580 if (event.getCause() != null)
581 {
582 cause = HangupCause.getByCode(event.getCause());
583 }
584
585 synchronized (channel)
586 {
587 channel.hungup(event.getDateReceived(), cause, event.getCauseTxt());
588 }
589
590 logger.info("Removing channel " + channel.getName() + " due to hangup (" + cause + ")");
591 removeOldChannels();
592 }
593
594 void handleDialEvent(DialEvent event)
595 {
596 final AsteriskChannelImpl sourceChannel = getChannelImplById(event.getUniqueId());
597 final AsteriskChannelImpl destinationChannel = getChannelImplById(event.getDestUniqueId());
598
599 if (sourceChannel == null)
600 {
601 logger.error("Ignored DialEvent for unknown source channel " + event.getChannel() + " with unique id " + event.getUniqueId());
602 return;
603 }
604 if (destinationChannel == null)
605 {
606 logger.error("Ignored DialEvent for unknown destination channel " + event.getDestination() + " with unique id " + event.getDestUniqueId());
607 return;
608 }
609
610 logger.info(sourceChannel.getName() + " dialed " + destinationChannel.getName());
611 getTraceId(sourceChannel);
612 getTraceId(destinationChannel);
613 synchronized (sourceChannel)
614 {
615 sourceChannel.channelDialed(event.getDateReceived(), destinationChannel);
616 }
617 synchronized (destinationChannel)
618 {
619 destinationChannel.channelDialing(event.getDateReceived(), sourceChannel);
620 }
621 }
622
623 void handleBridgeEvent(BridgeEvent event)
624 {
625 final AsteriskChannelImpl channel1 = getChannelImplById(event.getUniqueId1());
626 final AsteriskChannelImpl channel2 = getChannelImplById(event.getUniqueId2());
627
628 if (channel1 == null)
629 {
630 logger.error("Ignored BridgeEvent for unknown channel " + event.getChannel1());
631 return;
632 }
633 if (channel2 == null)
634 {
635 logger.error("Ignored BridgeEvent for unknown channel " + event.getChannel2());
636 return;
637 }
638
639 if (event.isLink())
640 {
641 logger.info("Linking channels " + channel1.getName() + " and " + channel2.getName());
642 synchronized (channel1)
643 {
644 channel1.channelLinked(event.getDateReceived(), channel2);
645 }
646
647 synchronized (channel2)
648 {
649 channel2.channelLinked(event.getDateReceived(), channel1);
650 }
651 }
652
653 if (event.isUnlink())
654 {
655 logger.info("Unlinking channels " + channel1.getName() + " and " + channel2.getName());
656 synchronized (channel1)
657 {
658 channel1.channelUnlinked(event.getDateReceived());
659 }
660
661 synchronized (channel2)
662 {
663 channel2.channelUnlinked(event.getDateReceived());
664 }
665 }
666 }
667
668 void handleRenameEvent(RenameEvent event)
669 {
670 AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
671
672 if (channel == null)
673 {
674 logger.error("Ignored RenameEvent for unknown channel with uniqueId " + event.getUniqueId());
675 return;
676 }
677
678 logger.info("Renaming channel '" + channel.getName() + "' to '" + event.getNewname() + "', uniqueId is " + event.getUniqueId());
679 synchronized (channel)
680 {
681 channel.nameChanged(event.getDateReceived(), event.getNewname());
682 }
683 }
684
685 void handleCdrEvent(CdrEvent event)
686 {
687 final AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
688 final AsteriskChannelImpl destinationChannel = getChannelImplByName(event.getDestinationChannel());
689 final CallDetailRecordImpl cdr;
690
691 if (channel == null)
692 {
693 logger.info("Ignored CdrEvent for unknown channel with uniqueId " + event.getUniqueId());
694 return;
695 }
696
697 cdr = new CallDetailRecordImpl(channel, destinationChannel, event);
698
699 synchronized (channel)
700 {
701 channel.callDetailRecordReceived(event.getDateReceived(), cdr);
702 }
703 }
704
705 private String getTraceId(AsteriskChannel channel)
706 {
707 String traceId;
708
709 try
710 {
711 traceId = channel.getVariable(Constants.VARIABLE_TRACE_ID);
712 }
713 catch (Exception e)
714 {
715 traceId = null;
716 }
717
718 return traceId;
719 }
720
721 void handleParkedCallEvent(ParkedCallEvent event)
722 {
723
724 AsteriskChannelImpl channel = getChannelImplByNameAndActive(event.getChannel());
725
726 if (channel == null)
727 {
728 logger.info("Ignored ParkedCallEvent for unknown channel "
729 + event.getChannel());
730 return;
731 }
732
733 synchronized (channel)
734 {
735
736
737 Extension ext = new Extension(null, event.getExten(), 1);
738 channel.setParkedAt(ext);
739 logger.info("Channel " + channel.getName() + " is parked at " + channel.getParkedAt().getExtension());
740 }
741 }
742
743 void handleParkedCallGiveUpEvent(ParkedCallGiveUpEvent event)
744 {
745
746 AsteriskChannelImpl channel = getChannelImplByNameAndActive(event.getChannel());
747
748 if (channel == null)
749 {
750 logger.info("Ignored ParkedCallGiveUpEvent for unknown channel "
751 + event.getChannel());
752 return;
753 }
754
755 Extension wasParkedAt = channel.getParkedAt();
756
757 if (wasParkedAt == null)
758 {
759 logger.info("Ignored ParkedCallGiveUpEvent as the channel was not parked");
760 return;
761 }
762
763 synchronized (channel)
764 {
765 channel.setParkedAt(null);
766 }
767 logger.info("Channel " + channel.getName() + " is unparked (GiveUp) from " + wasParkedAt.getExtension());
768 }
769
770 void handleParkedCallTimeOutEvent(ParkedCallTimeOutEvent event)
771 {
772
773 final AsteriskChannelImpl channel = getChannelImplByNameAndActive(event.getChannel());
774
775 if (channel == null)
776 {
777 logger.info("Ignored ParkedCallTimeOutEvent for unknown channel " + event.getChannel());
778 return;
779 }
780
781 Extension wasParkedAt = channel.getParkedAt();
782
783 if (wasParkedAt == null)
784 {
785 logger.info("Ignored ParkedCallTimeOutEvent as the channel was not parked");
786 return;
787 }
788
789 synchronized (channel)
790 {
791 channel.setParkedAt(null);
792 }
793 logger.info("Channel " + channel.getName() + " is unparked (Timeout) from " + wasParkedAt.getExtension());
794 }
795
796 void handleUnparkedCallEvent(UnparkedCallEvent event)
797 {
798
799 final AsteriskChannelImpl channel = getChannelImplByNameAndActive(event.getChannel());
800
801 if (channel == null)
802 {
803 logger.info("Ignored UnparkedCallEvent for unknown channel " + event.getChannel());
804 return;
805 }
806
807 Extension wasParkedAt = channel.getParkedAt();
808
809 if (wasParkedAt == null)
810 {
811 logger.info("Ignored UnparkedCallEvent as the channel was not parked");
812 return;
813 }
814
815 synchronized (channel)
816 {
817 channel.setParkedAt(null);
818 }
819 logger.info("Channel " + channel.getName() + " is unparked (moved away) from " + wasParkedAt.getExtension());
820 }
821
822 void handleVarSetEvent(VarSetEvent event)
823 {
824 if (event.getUniqueId() == null)
825 {
826 return;
827 }
828
829 final AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
830 if (channel == null)
831 {
832 logger.info("Ignored VarSetEvent for unknown channel with uniqueId " + event.getUniqueId());
833 return;
834 }
835
836 synchronized (channel)
837 {
838 channel.updateVariable(event.getVariable(), event.getValue());
839 }
840 }
841
842 void handleDtmfEvent(DtmfEvent event)
843 {
844
845 if (event.isBegin())
846 {
847 return;
848 }
849
850 if (event.getUniqueId() == null)
851 {
852 return;
853 }
854
855 final AsteriskChannelImpl channel = getChannelImplById(event.getUniqueId());
856 if (channel == null)
857 {
858 logger.info("Ignored DtmfEvent for unknown channel with uniqueId " + event.getUniqueId());
859 return;
860 }
861
862 final Character dtmfDigit;
863 if (event.getDigit() == null || event.getDigit().length() < 1)
864 {
865 dtmfDigit = null;
866 }
867 else
868 {
869 dtmfDigit = event.getDigit().charAt(0);
870 }
871
872 synchronized (channel)
873 {
874 if (event.isReceived())
875 {
876 channel.dtmfReceived(dtmfDigit);
877 }
878 if (event.isSent())
879 {
880 channel.dtmfSent(dtmfDigit);
881 }
882 }
883 }
884 }