/** * @return An immutable instance created from this mutable audio frame. In an ideal flow, this should never be called. */ public ImmutableAudioFrame freeze() { return new ImmutableAudioFrame(timecode, getData(), volume, format); } }
@Override public TrackFrameDataMessage decode(DataInput in, int version) throws IOException { long executorId = in.readLong(); int frameCount = in.readInt(); List<AudioFrame> frames = new ArrayList<>(frameCount); for (int i = 0; i < frameCount; i++) { long timecode = in.readLong(); byte[] data = new byte[in.readInt()]; in.readFully(data); frames.add(new ImmutableAudioFrame(timecode, data, in.readInt(), null)); } return new TrackFrameDataMessage(executorId, frames, in.readBoolean(), in.readLong()); } }
private AudioFrame filterFrame(AudioFrame frame) { if (frame != null && frame.getVolume() == 0) { return new ImmutableAudioFrame(frame.getTimecode(), format.silenceBytes(), 0, format); } return frame; }
private AudioFrame unwrapBridgeFrame() { if (bridgeFrame.isTerminator()) { return TerminatorAudioFrame.INSTANCE; } else { return new ImmutableAudioFrame(bridgeFrame.getTimecode(), bridgeFrame.getData(), bridgeFrame.getVolume(), bridgeFrame.getFormat()); } }
@Override public AudioFrame rebuild(AudioFrame frame) { if (frame.getVolume() == newVolume) { return frame; } decoder.decode(frame.getData(), sampleBuffer); int targetVolume = newVolume; if (++frameIndex < 50) { targetVolume = (int) ((newVolume - frame.getVolume()) * (frameIndex / 50.0) + frame.getVolume()); } // Volume 0 is stored in the frame with volume 100 buffer if (targetVolume != 0) { volumeProcessor.applyVolume(frame.getVolume(), targetVolume, sampleBuffer); } byte[] bytes = encoder.encode(sampleBuffer); // One frame per 20ms is consumed. To not spike the CPU usage, reencode only once per 5ms. By the time the buffer is // fully rebuilt, it is probably near to 3/4 its maximum size. try { Thread.sleep(5); } catch (InterruptedException e) { // Keep it interrupted, it will trip on the next interruptible operation Thread.currentThread().interrupt(); } return new ImmutableAudioFrame(frame.getTimecode(), bytes, targetVolume, format); }
private void handleTrackFrameData(TrackFrameDataMessage message) throws Exception { RemoteAudioTrackExecutor executor = playingTracks.get(message.executorId); if (executor != null) { if (message.seekedPosition >= 0) { executor.clearSeek(message.seekedPosition); } AudioFrameBuffer buffer = executor.getAudioBuffer(); executor.receivedData(); AudioDataFormat format = executor.getConfiguration().getOutputFormat(); for (AudioFrame frame : message.frames) { buffer.consume(new ImmutableAudioFrame(frame.getTimecode(), frame.getData(), frame.getVolume(), format)); } if (message.finished) { buffer.setTerminateOnEmpty(); trackEnded(executor, false); } } }