@Override public void stop() { frameBuffer.lockBuffer(); frameBuffer.setTerminateOnEmpty(); frameBuffer.clear(); markerTracker.trigger(STOPPED); remoteNodeManager.onTrackEnd(null, track, AudioTrackEndReason.STOPPED); }
/** * @return True if this track is currently in the middle of a seek. */ private boolean isPerformingSeek() { return queuedSeek.get() != -1 || (useSeekGhosting && frameBuffer.hasClearOnInsert()); }
@Override public boolean failedBeforeLoad() { return trackException != null && !frameBuffer.hasReceivedFrames(); }
private void applySeekState(long seekPosition) { state.set(AudioTrackState.SEEKING); if (useSeekGhosting) { frameBuffer.setClearOnInsert(); } else { frameBuffer.clear(); } queuedSeek.set(-1); markerTracker.checkSeekTimecode(seekPosition); }
@Override public AudioFrame provide() { AudioFrame frame = frameBuffer.provide(); processProvidedFrame(frame); return frame; }
private byte[] buildRequestBody() throws IOException { ByteArrayOutputStream outputBytes = new ByteArrayOutputStream(); DataOutputStream output = new DataOutputStream(outputBytes); List<RemoteMessage> messages = new ArrayList<>(); int queuedCount = queuedMessages.drainTo(messages); if (queuedCount > 0) { log.debug("Including {} queued messages in the request to {}.", queuedCount, nodeAddress); } for (RemoteAudioTrackExecutor executor : playingTracks.values()) { long pendingSeek = executor.getPendingSeek(); AudioFrameBuffer buffer = executor.getAudioBuffer(); int neededFrames = pendingSeek == -1 ? buffer.getRemainingCapacity() : buffer.getFullCapacity(); messages.add(new TrackFrameRequestMessage(executor.getExecutorId(), neededFrames, executor.getVolume(), pendingSeek)); } for (RemoteMessage message : messages) { mapper.encode(output, message); } mapper.endOutput(output); return outputBytes.toByteArray(); }
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); } } }
private void passThrough(ByteBuffer buffer) throws InterruptedException { offeredFrame.setTimecode(currentTimecode); offeredFrame.setBuffer(buffer); context.frameBuffer.consume(offeredFrame); }
/** * @return The expected timecode of the next frame to receive from the remote node. */ public long getNextInputTimecode() { boolean dataReceived = hasReceivedData; long frameDuration = configuration.getOutputFormat().frameDuration(); if (dataReceived) { Long lastBufferTimecode = frameBuffer.getLastInputTimecode(); if (lastBufferTimecode != null) { return lastBufferTimecode + frameDuration; } } long seekPosition = pendingSeek.get(); if (seekPosition != NO_SEEK) { return seekPosition; } return dataReceived ? lastFrameTimecode.get() + frameDuration : lastFrameTimecode.get(); }
@Override public void setPosition(long timecode) { if (!audioTrack.isSeekable()) { return; } synchronized (actionSynchronizer) { if (timecode < 0) { timecode = 0; } queuedSeek.set(timecode); if (!useSeekGhosting) { frameBuffer.clear(); } interruptForSeek(); } }
/** * Applies a volume level to the buffered frames of a frame consumer * @param context Configuration and output information for processing */ public static void apply(AudioProcessingContext context) { AudioFrameVolumeChanger volumeChanger = new AudioFrameVolumeChanger(context.configuration, context.outputFormat, context.playerOptions.volumeLevel.get()); try { volumeChanger.setupLibraries(); context.frameBuffer.rebuild(volumeChanger); } finally { volumeChanger.clearLibraries(); } } }
@Override public AudioFrame provide(long timeout, TimeUnit unit) throws TimeoutException, InterruptedException { AudioFrame frame = frameBuffer.provide(timeout, unit); processProvidedFrame(frame); return frame; }
@Override public void process(long timecode, ShortBuffer buffer) throws InterruptedException { outputBuffer.clear(); encoder.encode(buffer, outputBuffer); offeredFrame.setTimecode(timecode); offeredFrame.setVolume(context.playerOptions.volumeLevel.get()); offeredFrame.setBuffer(outputBuffer); context.frameBuffer.consume(offeredFrame); }
@Override public boolean provide(MutableAudioFrame targetFrame, long timeout, TimeUnit unit) throws TimeoutException, InterruptedException { if (frameBuffer.provide(targetFrame, timeout, unit)) { processProvidedFrame(targetFrame); return true; } return true; }
private void processProvidedFrame(AudioFrame frame) { if (frame != null && !frame.isTerminator()) { lastFrameTimecode.set(frame.getTimecode()); if (pendingSeek.get() == NO_SEEK && !frameBuffer.hasClearOnInsert()) { markerTracker.checkPlaybackTimecode(frame.getTimecode()); } } }
@Override public boolean provide(MutableAudioFrame targetFrame) { if (frameBuffer.provide(targetFrame)) { processProvidedFrame(targetFrame); return true; } return true; }
@Override public AudioFrame provide(long timeout, TimeUnit unit) throws TimeoutException, InterruptedException { AudioFrame frame = frameBuffer.provide(timeout, unit); processProvidedFrame(frame); return frame; }
@Override public boolean provide(MutableAudioFrame targetFrame) { if (frameBuffer.provide(targetFrame)) { processProvidedFrame(targetFrame); return true; } return false; }
@Override public AudioFrame provide() { AudioFrame frame = frameBuffer.provide(); processProvidedFrame(frame); return frame; }
@Override public boolean provide(MutableAudioFrame targetFrame, long timeout, TimeUnit unit) throws TimeoutException, InterruptedException { if (frameBuffer.provide(targetFrame, timeout, unit)) { processProvidedFrame(targetFrame); return true; } return true; }