/** * Find a call by callId. * * <p>Calls are kept in the activeCalls list and uniquely identified by * <callId>::<name>@<phoneNumber> for a phone call and * * <p>This method searches for a call with the callId. */ public static CallHandler findCall(String callId) { if (Logger.logLevel >= Logger.LOG_DETAIL) { Logger.println( "findCall: looking for " + callId + ", " + activeCalls.size() + " active calls"); } synchronized (activeCalls) { for (int i = 0; i < activeCalls.size(); i++) { CallHandler call = (CallHandler) activeCalls.elementAt(i); CallParticipant cp = call.getCallParticipant(); if (Logger.logLevel >= Logger.LOG_DETAIL) { Logger.println("findCall: looking for " + callId + " got " + cp.getCallId()); } if (match(cp, callId)) { if (Logger.logLevel >= Logger.LOG_DETAIL) { Logger.println("findCall: found " + callId); } return call; } } } return null; }
/** Send indication when a dtmf key is pressed */ public void dtmfKeys(String dtmfKeys) { // if (Logger.logLevel >= Logger.LOG_MOREINFO) { Logger.println(cp + " got dtmf keys " + dtmfKeys + " " + cp.dtmfDetection()); // } if (isCallEstablished()) { if (cp.dtmfDetection()) { member.stopTreatment(null); CallEvent callEvent = new CallEvent(CallEvent.DTMF_KEY); callEvent.setDtmfKey(dtmfKeys); sendCallEventNotification(callEvent); } if (otherCall != null) { Logger.println("Call " + cp + " forwarding dtmf key " + dtmfKeys + " to " + otherCall); otherCall.getMemberSender().setDtmfKeyToSend(dtmfKeys); } else { getMemberSender().setDtmfKeyToSend(dtmfKeys); } } else { if (Logger.logLevel >= Logger.LOG_MOREINFO) { Logger.println(cp + " Call not established, ignoring dtmf"); } stopCallAnsweredTreatment(); } }
/** Done with treatments for call end, now terminate the call */ public void terminateCall() { if (receivedBye == false) { if (gotOk == false || (getState() == CallState.INVITED && callAnswered == false)) { try { Logger.writeFile("Call " + cp + ": sendCancel"); sipUtil.sendCancel(clientTransaction); } catch (Exception e) { Logger.println("sendCancel " + e.getMessage()); } } else { /* * Try sending a BYE as well. * Seems that when we treat SESSION_PROGRESS * as OK, sometimes we need to send a CANCEL * and other times a BYE. We'll send both. */ try { Logger.writeFile("Call " + cp + ": sendBye"); sipUtil.sendBye(clientTransaction); } catch (Exception e) { Logger.println("Call " + cp + ": sendBye" + e.getMessage()); } } } }
public String noDataReceived() { /* * Create a packet of silence (linear 0) * The dtmf detector needs to know when a dtmf key * is released. If a phone stops sending immediately * after the dtmf key is released, we need to append * silence so that the dtmf detector will return * the dtmf key. */ int[] silence = new int[mediaInfo.getSamplesPerPacket()]; String dtmfKeys = null; dtmfKeys = processData(silence); if (Logger.logLevel >= Logger.LOG_DETAIL) { Logger.println("no data received, done processing dtmf with silence"); if (dtmfKeys != null) { Logger.println("silence. dtmf " + dtmfKeys); } } return dtmfKeys; }
private void startSpeaker(AudioFormat format) throws LineUnavailableException { speaker.open(format, bufferSize); int actualBufferSize = speaker.getBufferSize(); if (bufferSize != actualBufferSize) { Logger.println( "Speaker set buffer to " + bufferSize + " but actual size is " + actualBufferSize); bufferSize = actualBufferSize; } if (Logger.logLevel >= Logger.LOG_MOREINFO) { Logger.println( "Speaker using " + getBufferSizeMillis(actualBufferSize) + " millisecond buffer " + actualBufferSize + " bytes"); } speaker.start(); flush(); // println("speaker started"); }
/* * Remove call from list of active calls */ public void removeCall(CallHandler callHandler) { synchronized (activeCalls) { activeCalls.remove(callHandler); // remove call from list Logger.println(""); Logger.println("calls still in progress: " + activeCalls.size()); Logger.println(""); } }
public static void main(String[] args) { if (args.length != 1) { Logger.println("Usage: java Speaker <input file>"); System.exit(1); } BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); Speaker speaker = null; while (true) { try { speaker = new SpeakerJavasoundImpl( 8000, 1, RtpPacket.getDataSize(RtpPacket.PCM_ENCODING, 8000, 1)); } catch (Exception e) { Logger.println(e.getMessage()); System.exit(1); } Logger.logLevel = 5; try { TreatmentManager t = new TreatmentManager(args[0], 0, speaker.getSampleRate(), speaker.getChannels()); while (true) { byte[] audioData = t.getLinearDataBytes(RtpPacket.PACKET_PERIOD); if (audioData == null) { break; // end of file } speaker.write(audioData, 0, audioData.length); } } catch (IOException e) { Logger.println(e.getMessage()); } if (speaker != null) { speaker.done(); } Logger.println("Press return to play the file again..."); try { String line = br.readLine(); if (line.equalsIgnoreCase("quit")) { break; } } catch (IOException ioe) { break; } } }
public void printStatistics() { Logger.println(getName() + " " + packetsSent + " packets sent"); if (packetsSent > 0) { Logger.println( getName() + " average time to send a packet to every member " + (totalSendTime / 1000000000. / packetsSent) + " seconds "); } ticker.printStatistics(); }
public void printStatistics() { Logger.writeFile( "Call " + memberReceiver.toString() + ": " + "Dtmf detector calls: " + numberOfTimesCalled); if (numberOfTimesCalled != 0) { Logger.writeFile( memberReceiver.toString() + ": Dtmf decoder average ms per call: " + ((float) ((float) totalDecodeTime / numberOfTimesCalled))); } }
public void run() { while (!done) { try { ConferenceMember member = (ConferenceMember) workToDo.remove(); try { member.sendData(); } catch (Exception e) { e.printStackTrace(); Logger.println("Can't send data to " + member + " " + e.getMessage()); member.getCallHandler().cancelRequest("Unexpected Exception"); } } catch (NoSuchElementException e) { synchronized (this) { doneSignal.countDown(); if (done) { break; // done } try { wait(); } catch (InterruptedException ie) { break; } } } } }
/** Mute or unmute the main conference from a particular call. */ public static void setConferenceSilenced(String callId, boolean isSilenced) { synchronized (activeCalls) { for (int i = 0; i < activeCalls.size(); i++) { CallHandler call = (CallHandler) activeCalls.elementAt(i); CallParticipant cp = call.getCallParticipant(); if (match(cp, callId)) { if (Logger.logLevel >= Logger.LOG_DETAIL) { String s = ""; if (isSilenced == false) { s = "un"; } Logger.println(cp.getCallId() + ": silenceMainonference " + s + "muted"); } ConferenceMember member = call.getMember(); if (member != null) { member.setConferenceSilenced(isSilenced); } } } } }
/** Mute or unmute member in a whisperGroup */ public static void setMuteWhisperGroup(String callId, boolean isMuted) { if (callId == null) { return; } synchronized (activeCalls) { for (int i = 0; i < activeCalls.size(); i++) { CallHandler call = (CallHandler) activeCalls.elementAt(i); CallParticipant cp = call.getCallParticipant(); if (match(cp, callId)) { if (Logger.logLevel >= Logger.LOG_DETAIL) { String s = ""; if (isMuted == false) { s = "un"; } Logger.println(cp.getCallId() + ": " + s + "muted"); } MemberReceiver memberReceiver = call.getMemberReceiver(); if (memberReceiver != null) { memberReceiver.setMuteWhisperGroup(isMuted); } } } } }
public DtmfDecoder(MemberReceiver memberReceiver, MediaInfo mediaInfo) { this.memberReceiver = memberReceiver; this.mediaInfo = mediaInfo; decoder = new Decoder(); linearData = new int[mediaInfo.getSamplesPerPacket()]; decoder.setRate(mediaInfo.getSampleRate()); if (mediaInfo.getChannels() != 1) { /* * Must convert multi-channel to 1 */ try { sampleRateConverter = new SampleRateConverter( "DtmfDecoder", mediaInfo.getSampleRate(), mediaInfo.getChannels(), mediaInfo.getSampleRate(), 1); } catch (IOException e) { Logger.println("Call " + memberReceiver + " DtmfDecoder: " + e.getMessage()); } } }
public synchronized void done() { if (done) { return; } done = true; /* * There seems to be a bug in the Sun Ray audio system * where close() hangs sometimes if there is still data * in the speaker buffer. By sleeping for the time * it would take to empty a full buffer (plus some slop), * the close() seems to always complete. * * XXX */ try { Thread.sleep(getBufferSizeMillis() + RtpPacket.PACKET_PERIOD); } catch (InterruptedException e) { } synchronized (speaker) { speaker.flush(); speaker.stop(); speaker.close(); } if (Logger.logLevel >= Logger.LOG_MOREINFO) { Logger.println("Speaker closed"); } }
public void setVolumeLevel(double volumeLevel) { this.volumeLevel = volumeLevel; if (Logger.logLevel >= Logger.LOG_MOREINFO) { Logger.println("Setting Speaker volume to " + volumeLevel); } Utils.setPreference(VOLUME_LEVEL, String.valueOf(volumeLevel)); }
private void handleReInvite(Request request, ServerTransaction st) { Logger.println("Call " + cp + " Re-INVITE\n" + request); if (request.getRawContent() == null) { Logger.error("Call " + cp + " no SDP in INVITE Request!"); return; } String sdpBody = new String(request.getRawContent()); SdpInfo sdpInfo; try { sdpInfo = sipUtil.getSdpInfo(sdpBody); } catch (ParseException e) { Logger.error("Call " + cp + " invalid SDP in re-INVITE Request! " + e.getMessage()); return; } MediaInfo mediaInfo = sdpInfo.getMediaInfo(); InetSocketAddress isa = new InetSocketAddress(sdpInfo.getRemoteHost(), sdpInfo.getRemotePort()); InetSocketAddress rtcpAddress = sdpInfo.getRtcpAddress(); setEndpointAddress( isa, mediaInfo.getPayload(), sdpInfo.getTransmitMediaInfo().getPayload(), sdpInfo.getTelephoneEventPayload(), rtcpAddress); isa = callHandler.getReceiveAddress(); try { sipUtil.sendOkWithSdp(request, st, isa, sdpInfo); } catch (Exception e) { Logger.println("Call " + cp + " Failed to send ok with sdp for re-invite " + e.getMessage()); return; } }
private boolean setupSpeaker(String device) throws LineUnavailableException { Mixer.Info[] aInfos = AudioSystem.getMixerInfo(); for (int i = 0; i < aInfos.length; i++) { Mixer.Info mixerInfo = aInfos[i]; if (GetDataLines.equals(device, mixerInfo) == false) { if (Logger.logLevel >= Logger.LOG_MOREINFO) { Logger.println("Skipping: " + mixerInfo.getName() + "," + mixerInfo.getDescription()); } continue; } try { Mixer mixer = AudioSystem.getMixer(mixerInfo); Line.Info[] infos = mixer.getSourceLineInfo(); for (int j = 0; j < infos.length; j++) { Line line = (Line) mixer.getLine(infos[j]); if (line instanceof SourceDataLine) { speaker = (SourceDataLine) line; if (Logger.logLevel >= Logger.LOG_INFO) { Logger.println("Found speaker: " + j); } break; } } } catch (Exception e) { if (Logger.logLevel >= Logger.LOG_MOREINFO) { Logger.println("Exception: " + e.getMessage()); } } } return speaker != null; }
/** * Processes SIP requests. The only request being handled is BYE. * * @param requestReceivedEvent the event containing the SIP request */ public synchronized void processRequest(RequestEvent requestReceivedEvent) { // obtain request and transaction id Request request = requestReceivedEvent.getRequest(); ServerTransaction st = requestReceivedEvent.getServerTransaction(); if (request.getMethod().equals(Request.BYE)) { handleBye(request, st); } else if (request.getMethod().equals(Request.INVITE)) { /* * This is a re-Invite */ handleReInvite(request, st); } else if (request.getMethod().equals(Request.ACK)) { Logger.println("Call " + cp + " got ACK"); } else { // no other requests should come in other than BYE, INVITE or ACK Logger.writeFile("Call " + cp + " ignoring request " + request.getMethod()); } }
/** * handles a BYE request * * @param request the request * @param transId the transaction Id * @throws TransactionDoesNotExistException when the transaction record does not exist. */ private void handleBye(Request request, ServerTransaction st) { try { CallIdHeader callIdHeader = (CallIdHeader) request.getHeader("Call-Id"); String sipCallId = callIdHeader.getCallId(); if (sipCallId.equals(this.sipCallId)) { receivedBye = true; try { Logger.writeFile("Call " + cp + " has hung up."); // sipUtil.sendOK(clientTransaction, st, cp); sipUtil.sendOK(request, st); } catch (Exception e) { /* * We sometimes get a null ServerTransaction */ } cancelRequest("hung up"); sipServerCallback.removeSipListener(sipCallId); } else { /* * this should not happen since the message has been * delegated to this sip agent. */ throw new TransactionDoesNotExistException( cp + "BYE request received did not " + "match either party: " + request); } } catch (TransactionDoesNotExistException e) { Logger.error("Call " + cp + " Transaction not found " + e.getMessage()); } catch (SipException e) { Logger.exception("Call " + cp + " SIP Stack error", e); cancelRequest("handleBye: SIP Stack error " + e.getMessage()); } catch (Exception e) { Logger.exception("Call " + cp + " Unknown error ", e); cancelRequest("handleBye: SIP Stack error " + e.getMessage()); } }
/* * terminate a call. */ public void cancelRequest(String reason) { if (done) { return; } done = true; Logger.println(cp + " Cancel request " + reason); if (csa != null) { csa.cancelRequest(reason); } }
/* * data starts at RtpPacket.HEADER_SIZE */ public String processData(int[] linearData) { numberOfTimesCalled++; long start = System.currentTimeMillis(); if (sampleRateConverter != null) { try { int nSamples = linearData.length; linearData = sampleRateConverter.resample(linearData); if (Logger.logLevel >= Logger.LOG_DETAIL) { Logger.println( "Resample for Dtmf: nSamples " + nSamples + " new nSamples " + linearData.length); } } catch (IOException e) { Logger.println("Call " + memberReceiver + " DtmfDecoder: " + e.getMessage()); } } int keys[] = new int[MAX_KEYS]; // decoded key int nkeys = decoder.decode(keys, AudioConversion.intsToShorts(linearData), 0); String dtmfKeys = null; if (nkeys > 0) { char[] charKeys = new char[nkeys]; for (int i = 0; i < nkeys; i++) { charKeys[i] = char_keys[keys[i]]; } dtmfKeys = new String(charKeys); } totalDecodeTime += (System.currentTimeMillis() - start); return dtmfKeys; }
private void singleThreadSendDataToMembers(ArrayList memberList) { for (int i = 0; i < memberList.size(); i++) { ConferenceMember member = (ConferenceMember) memberList.get(i); if (!member.getMemberSender().memberIsReadyForSenderData()) { continue; } long start = 0; if (Logger.logLevel == -33) { start = System.nanoTime(); } try { member.sendData(); } catch (Exception e) { e.printStackTrace(); Logger.println("Can't send data to " + member + " " + e.getMessage()); member.getCallHandler().cancelRequest("Unexpected Exception"); } if (Logger.logLevel == -33) { Logger.println( "Sender sendDataToOneMember time " + member + " " + ((System.nanoTime() - start) / 1000000000.) + " seconds"); Logger.logLevel = 3; } } }
public synchronized int write(byte[] buffer, int offset, int length) { if (speaker == null) { return 0; } start(); /* * Break the buffer up into 20 ms chunks, write as much as we can, * then wait until there's room for more. */ int len = length; int sleepCount = 0; long start = System.currentTimeMillis(); while (len > 0) { int writeLength = Math.min(len, chunkSize); while (!done && available() < chunkSize) { try { Thread.sleep(RtpPacket.PACKET_PERIOD); sleepCount++; } catch (InterruptedException e) { } } applyVolume(buffer, offset, writeLength); speaker.write(buffer, offset, writeLength); offset += writeLength; len -= writeLength; } if (sleepCount > 0) { if (Logger.logLevel >= Logger.LOG_MOREINFO) { long elapsed = System.currentTimeMillis() - start; Logger.println("write to speaker slept " + sleepCount + " times, " + elapsed + "ms"); } } numWrites++; return length; }
/** Find the new call of a call migration. */ public static CallHandler findMigratingCall(String callId) { synchronized (activeCalls) { for (int i = 0; i < activeCalls.size(); i++) { CallHandler call = (CallHandler) activeCalls.elementAt(i); CallParticipant cp = call.getCallParticipant(); if (match(cp, callId) && cp.migrateCall()) { if (Logger.logLevel >= Logger.LOG_DETAIL) { Logger.println("findMigratingCall: found " + callId); } return call; } } } return null; }
public static void setDoNotRecord(String callId, boolean doNotRecord) throws NoSuchElementException { CallHandler callHandler = findCall(callId); if (callHandler == null) { throw new NoSuchElementException("Invalid callId specified: " + callId); } if (Logger.logLevel >= Logger.LOG_DETAIL) { String s = ""; if (doNotRecord == true) { s = "NOT"; } Logger.println(callHandler + ": " + s + " okay to record"); } callHandler.getMemberReceiver().setDoNotRecord(doNotRecord); }
/* * Begin Third-Party Call Control. */ public void initiateCall() throws IOException { try { try { busyTreatment = new TreatmentManager("busy.au", 0); } catch (IOException e) { Logger.println("Invalid busy treatment: " + e.getMessage()); } Logger.writeFile("Call " + cp + ": Begin SIP third party call"); setState(CallState.INVITED); InetSocketAddress isa = callHandler.getReceiveAddress(); if (isa == null) { throw new IOException("can't get receiver socket!"); } // send INVITE to the CallParticipant clientTransaction = sipUtil.sendInvite(cp, isa); if (clientTransaction == null) { Logger.error("Error placing call: " + cp); setState(CallState.ENDED, "Reason='Error placing call'"); throw new IOException("Error placing call: " + cp); } CallIdHeader callIdHeader = (CallIdHeader) clientTransaction.getRequest().getHeader(CallIdHeader.NAME); sipCallId = callIdHeader.getCallId(); sipServerCallback = SipServer.getSipServerCallback(); sipServerCallback.addSipListener(sipCallId, this); } catch (java.text.ParseException e) { Logger.println("Call " + cp + " Error placing call " + cp + ": " + e.getMessage()); setState(CallState.ENDED, "Reason='Error placing call " + cp + " " + e.getMessage() + "'"); throw new IOException("Error placing call " + cp + " " + e.getMessage()); } catch (InvalidArgumentException e) { Logger.println("Call " + cp + " Error placing call " + cp + ": " + e.getMessage()); setState(CallState.ENDED, "Reason='Error placing call " + cp + " " + e.getMessage() + "'"); throw new IOException("Error placing call " + cp + " " + e.getMessage()); } catch (SipException e) { Logger.println("Call " + cp + " Error placing call " + cp + ": " + e.getMessage()); setState(CallState.ENDED, "Reason='Error placing call " + cp + " " + e.getMessage() + "'"); throw new IOException("Error placing call " + cp + " " + e.getMessage()); } }
public TreatmentManager playTreatmentToCall( String treatment, TreatmentDoneListener treatmentDoneListener) throws IOException { if (Logger.logLevel >= Logger.LOG_MOREINFO) { Logger.println("Playing treatment " + treatment + " to " + cp.getCallId()); } TreatmentManager treatmentManager = new TreatmentManager( treatment, 0, conferenceManager.getMediaInfo().getSampleRate(), conferenceManager.getMediaInfo().getChannels()); if (treatmentDoneListener != null) { treatmentManager.addTreatmentDoneListener(treatmentDoneListener); } addTreatment(treatmentManager); return treatmentManager; }
/** Set flag to do voice detection while muted */ public static void setVoiceDetectionWhileMuted(String callId, boolean voiceDetectionWhileMuted) { if (callId == null) { return; } synchronized (activeCalls) { for (int i = 0; i < activeCalls.size(); i++) { CallHandler call = (CallHandler) activeCalls.elementAt(i); CallParticipant cp = call.getCallParticipant(); if (match(cp, callId)) { cp.setVoiceDetectionWhileMuted(voiceDetectionWhileMuted); if (Logger.logLevel >= Logger.LOG_DETAIL) { Logger.println( cp.getCallId() + " voice detection while muted is " + voiceDetectionWhileMuted); } } } } }
public SpeakerJavasoundImpl(int sampleRate, int channels, int bufferSize) throws IOException { this.sampleRate = sampleRate; this.channels = channels; this.bufferSize = bufferSize; chunkSize = RtpPacket.getDataSize(RtpPacket.PCM_ENCODING, sampleRate, channels); try { setupSpeaker(); } catch (LineUnavailableException e) { throw new IOException(e.getMessage()); } if (Logger.logLevel >= Logger.LOG_INFO) { Logger.println("New speaker " + sampleRate + "/" + channels + " bufferSize " + bufferSize); } double volumeLevel = Utils.getDoublePreference(VOLUME_LEVEL); if (volumeLevel != -1D) { this.volumeLevel = volumeLevel; } }
public void processIOException(IOExceptionEvent ioee) { if (Logger.logLevel >= Logger.LOG_SIP) { Logger.println("processTransactionTerminated called"); } }