📄 voicespeakeroutput.java
字号:
} /** * Return the call control object */ protected VoJxtaCallControl getCallControl() { return this.callControl; } /** * Retrieves the command (as String) from this DialogMessage. * * @param msg DialogMessage containing the command string * @return String command */ private String getMessageSessionCommand(DialogMessage msg) { String command = null; MessageElement commandMessageElement = msg.getMessageElement(VoJxtaCallControl.TAG_SESSION_COMMAND); if (commandMessageElement != null) { if (true || commandMessageElement instanceof ByteArrayMessageElement) { command = commandMessageElement.toString(); } else { if (LOG.isEnabledFor(Level.INFO)) { LOG.info("getMessageSessionCommand is not instanceof ByteArrayMessageElement"); } } } else { if (LOG.isEnabledFor(Level.INFO)) { LOG.info("sessionMessageCommandElement is null"); } } return command; } /** * Retrieves the data element from this DialogMessage and returns the speex * encoded bytes. * * @param msg The DialogMessage containing voice data * @return voiceData actual speex encoded bytes */ private byte[] getMessageVoiceBytes(DialogMessage msg) { byte[] voiceData = null; MessageElement voiceMessageElement = msg.getMessageElement(VoJxtaCallControl.TAG_VOICE_DATA); if (voiceMessageElement != null) { if (voiceMessageElement instanceof ByteArrayMessageElement) { ByteArrayMessageElement voiceDataElelment = (ByteArrayMessageElement) voiceMessageElement; voiceData = voiceDataElelment.getBytes(); } else { if (LOG.isEnabledFor(Level.INFO)) { LOG.info("getMessageVoiceBytes VOICE DATA Element is not instanceof ByteMessageElement"); } } } else { if (LOG.isEnabledFor(Level.INFO)) { LOG.info("voiceMessageElement is null"); } } return voiceData; } /** * Decode and write decoded bytes to pcmBuffer. we pull a chunk of * speex bytes of speexMessageSize into this method then block it out * to its basic block size (determined by speex quality) and write the * raw pcm to the pcmBuffer. the decoded block size is 640 bytes at the * current sample rate. * ie * speexMessageSize = 75 bytes (5 chunks of 15bytes) * break the message up into 5 chunks and decode each * put it all together and write to pcmBufer * <p/> * SourceLine writes do large chunks better than rapid small chunks (640) * so we put a message back together and write it to the pcmBuffer */ protected void decodeAndPlay(byte[] buf) { if (getSpeakerState() != this.STATE_OFF || getSpeakerState() != this.STATE_PAUSE) { int chunks = buf.length / speexChunkSize; byte[] decodedBuff = new byte[chunks * rawChunkSize]; int[] encodedStartPos = new int[chunks]; int[] decodedStartPos = new int[chunks]; for (int j = 0; j < chunks; j++) { encodedStartPos[j] = j * speexChunkSize; decodedStartPos[j] = j * rawChunkSize; } for (int i = 0; i < chunks; i++) { byte[] preDecodeBuff = new byte[speexChunkSize]; System.arraycopy(buf, encodedStartPos[i], preDecodeBuff, 0, speexChunkSize); long in = System.currentTimeMillis(); byte[] postDecodeBuff = decoder.decode(preDecodeBuff); long out = System.currentTimeMillis(); long roundTrip = (out - in); if (averageDecodeTime != 0) { averageDecodeTime = (long) (averageDecodeTime + roundTrip) / 2; } else { averageDecodeTime = roundTrip; } System.arraycopy(postDecodeBuff, 0, decodedBuff, decodedStartPos[i], rawChunkSize); } boolean sourceLineWaiting = false; synchronized (sourceLineThreadWaiting) { sourceLineWaiting = sourceLineThreadWaiting.booleanValue(); } if (sourceLineWaiting && sourceLineThread.getBufferSize() >= sourceLineThread.getWriteBlockSize()) { messageThreadWaiting = new Boolean(false); synchronized (sourceLineThreadLock) { sourceLineThreadLock.notify(); } } sourceLineThread.put(decodedBuff); //sourceLine.write (decodedBuff, 0, decodedBuff.length); } else { LOG.info("Unable to play audio, line closed!"); } } /** * Statistical accessor */ public int getPCMBufferSize() { return sourceLineThread != null ? sourceLineThread.getBufferSize() : -1; } /** * Statistical accessor */ public int getSourceLineAvailable() { return sourceLine.available(); } /** * This thread holds a dynamic buffer from which decoded bytes are written. * Largish chunks (multiples of rawPCMBlockSize) are read and written to * the source line when source line buffer has room and there are ample * bytes in the pcmBuffer. This Thread does the actual Playing to the * speaker. * TODO: * The pause state is recognized in this thread which will halt the * playing of sound but a signal needs to be sent to the main VoiceSpekaerOutput * run() or else hte buffers will continue to fill. */ class WriteToSourceLineThread extends Thread { private VoiceDataBuffer pcmBuffer = null; private int writeBlockSize = rawChunkSize * 30; private int pcmBufferSize = rawBufferSize * 60; WriteToSourceLineThread() { pcmBuffer = new VoiceDataBuffer(pcmBufferSize, VoiceSpeakerOutput.this, "WriteToSourceLineThread"); setPriority(Thread.NORM_PRIORITY); } public int getWriteBlockSize() { return writeBlockSize; } public int getBufferSize() { return pcmBuffer.size(); } public void put(byte[] buff) { pcmBuffer.append(buff); } public void run() { if (LOG.isEnabledFor(Level.INFO)) { LOG.info("WriteToSourceLineThread : run begin"); } while (true) { try { if (getSpeakerState() == VoiceSpeakerOutput.this.STATE_PAUSE) { if (LOG.isEnabledFor(Level.INFO)) { LOG.info("WriteToSourceLineThread run : is paused"); } synchronized (pauseLock) { pauseLock.wait(); } } if (getSpeakerState() == VoiceSpeakerOutput.this.STATE_OFF) { if (LOG.isEnabledFor(Level.INFO)) { LOG.info("WriteToSourceLineThread run : is off"); } //we should send any remaining data in buffer first break; } //if( sourceLine.available () >= writeBlockSize && // pcmBuffer.size () > writeBlockSize) { if (pcmBuffer.size() > (640)) { int l = pcmBuffer.size(); sourceLine.write(pcmBuffer.get(l), 0, l); //sourceLine.write (pcmBuffer.get (writeBlockSize), 0, writeBlockSize); } else { synchronized (sourceLineThreadWaiting) { sourceLineThreadWaiting = new Boolean(true); } synchronized (sourceLineThreadLock) { if (LOG.isEnabledFor(Level.INFO)) { //LOG.info ("Waiting for new PCM Blocks.."); } sourceLineThreadLock.wait(); } } } catch (InterruptedException ix) { ix.printStackTrace(); } } if (LOG.isEnabledFor(Level.INFO)) { LOG.info("WriteToSourceLineThread : run end"); } } } private int getSpeakerState() { return this.speakerState; } /** * halts writing to the source line (speaker). race condition exists. fix */ public void pauseSpeaker() { setSpeakerState(this.STATE_PAUSE); sourceLine.stop(); } /** * Resumes writing to the sourceLine and starts the line */ public void resumeSpeaker() { sourceLine.start(); setSpeakerState(this.STATE_ON); synchronized (pauseLock) { pauseLock.notify(); } } /** * Accessor for incoming speex buffer size */ public int getEncodedBufferSize() { return speexBufferSize; } /** * Accessor for incoming speex buffer size */ public void setEncodedBufferSize(int encodedBufferSize) { // at the momment the buffer is not resizeable //this.speexBufferSize = encodedBufferSize; } /** * statistical accessor */ public long getNumberOfMessagesReceived() { return this.receivedMessages; } /** * statistical accessor */ public long getNumberOfBytesReceived() { return this.receivedBytes; } /** * statistical accessor */ public long getAverageDecodeTime() { return averageDecodeTime; } /** * statistical accessor */ public int getEncodedMessageSize() { return speexMessageSize; } /** * statistical accessor */ public void setEncodedMessageSize(int encodedMessageSize) { this.speexMessageSize = encodedMessageSize; } /** * statistical accessor */ public boolean isGainControlSupported() { return gainControl != null; } /** * Sets the gain on this source Line */ public void adjustGainValue(float gainValue) { if (gainControl != null) { gainControl.setValue(gainValue); } } /** * Returns the current gain value. */ public float getGainValue() { return (gainControl != null) ? gainControl.getValue() : 0.0f; } /** * Returns the max gain value for this sourceline */ public float getMaxGainValue() { return (gainControl != null) ? gainControl.getMaximum() : 0.0f; } /** * Returns the min gain value for this sourceline */ public float getMinGainValue() { return (gainControl != null) ? gainControl.getMinimum() : 0.0f; } /** * Returns a string representing the units this gain control uses */ public String getGainUnits() { return (gainControl != null) ? gainControl.getUnits() : ""; } /** * Returns a string representing the max value as a label */ public String getMaxGainLabel() { return (gainControl != null) ? gainControl.getMaxLabel() : ""; } /** * Returns a string representing the min value as a label */ public String getMinGainLabel() { return (gainControl != null) ? gainControl.getMinLabel() : ""; } /** * Querys control state */ public boolean isMuteControlSupported() { return muteControl != null; } /** * Querys control state */ public boolean isMute() { return muteControl.getValue(); } /** * sets control state */ public void setMute(boolean mute) { muteControl.setValue(mute); } /** * Querys control unit string */ public String getMuteStateLabel() { return muteControl.getStateLabel(muteControl.getValue()); } private void printMixers() { System.out.println("\n\rSpeakerMixers : "); Mixer.Info[] info = AudioSystem.getMixerInfo(); for (int i = 0; i < info.length; i++) { System.out.println("\tName: " + info[i].getName() + " Description: " + info[i].getDescription()); } } private void printControls() { System.out.println("\n\rSpeakerControls : "); Control[] controls = sourceLine.getControls(); for (int i = 0; i < controls.length; i++) { System.out.println("\tName: " + controls[i].toString()); } } /** * debugging */ private void printSpeakerState() { String s = null; if (this.speakerState == STATE_PAUSE) { s = "PAUSE "; } if (this.speakerState == STATE_ON) { s = "ON "; } if (this.speakerState == STATE_OFF) { s = "OFF "; } if (LOG.isEnabledFor(Level.INFO)) { LOG.info("printMicState = " + s); } } protected void printSupportedControls() { LOG.info("Speaker SupportedControls"); LOG.info("mute " + sourceLine.isControlSupported(BooleanControl.Type.MUTE)); LOG.info("Balance " + sourceLine.isControlSupported(FloatControl.Type.BALANCE)); LOG.info("MasterGain " + sourceLine.isControlSupported(FloatControl.Type.MASTER_GAIN)); LOG.info("Pan " + sourceLine.isControlSupported(FloatControl.Type.PAN)); LOG.info("SampleRate " + sourceLine.isControlSupported(FloatControl.Type.SAMPLE_RATE)); LOG.info("Volume " + sourceLine.isControlSupported(FloatControl.Type.VOLUME)); Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo(); for (int i = 0; i < mixerInfo.length; i++) { speakerMixer = AudioSystem.getMixer(mixerInfo[i]); LOG.info("speakerMixer SupportedControls for mixer" + mixerInfo[i].toString()); LOG.info("mute " + speakerMixer.isControlSupported(BooleanControl.Type.MUTE)); LOG.info("Balance " + speakerMixer.isControlSupported(FloatControl.Type.BALANCE)); LOG.info("MasterGain " + speakerMixer.isControlSupported(FloatControl.Type.MASTER_GAIN)); LOG.info("Pan " + speakerMixer.isControlSupported(FloatControl.Type.PAN)); LOG.info("SampleRate " + speakerMixer.isControlSupported(FloatControl.Type.SAMPLE_RATE)); LOG.info("Volume " + speakerMixer.isControlSupported(FloatControl.Type.VOLUME)); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -