From fa029b265c0836f75373fba73c52e1c622e92ef7 Mon Sep 17 00:00:00 2001 From: dalgwen Date: Mon, 10 Jan 2022 08:56:38 +0100 Subject: [PATCH] [audio] Remove 'clac' noise when playing wave (javasound) (#2670) * [audio] Remove 'clac' noise when playing wav (javasound) A 'clac' can be heard at the beginning of a wav file when playing on the javasound sink. Close #2669 Signed-off-by: Gwendal Roulleau --- .../audio/internal/javasound/AudioPlayer.java | 11 +++++++- .../core/audio/utils/AudioWaveUtils.java | 28 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/bundles/org.openhab.core.audio/src/main/java/org/openhab/core/audio/internal/javasound/AudioPlayer.java b/bundles/org.openhab.core.audio/src/main/java/org/openhab/core/audio/internal/javasound/AudioPlayer.java index 1eeddc2906..872a77bb63 100644 --- a/bundles/org.openhab.core.audio/src/main/java/org/openhab/core/audio/internal/javasound/AudioPlayer.java +++ b/bundles/org.openhab.core.audio/src/main/java/org/openhab/core/audio/internal/javasound/AudioPlayer.java @@ -25,6 +25,7 @@ import javax.sound.sampled.SourceDataLine; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.audio.AudioStream; +import org.openhab.core.audio.utils.AudioWaveUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -60,7 +61,10 @@ public class AudioPlayer extends Thread { @Override public void run() { SourceDataLine line; - AudioFormat audioFormat = convertAudioFormat(this.audioStream.getFormat()); + + org.openhab.core.audio.AudioFormat openhabAudioFormat = audioStream.getFormat(); + + AudioFormat audioFormat = convertAudioFormat(openhabAudioFormat); if (audioFormat == null) { logger.warn("Audio format is unsupported or does not have enough details in order to be played"); return; @@ -87,6 +91,11 @@ public class AudioPlayer extends Thread { int nRead = 0; byte[] abData = new byte[65532]; // needs to be a multiple of 4 and 6, to support both 16 and 24 bit stereo try { + // If this is a wav container, we should remove the header from the stream + // to avoid a "clack" noise at the beginning + if (org.openhab.core.audio.AudioFormat.CONTAINER_WAVE.equals(openhabAudioFormat.getContainer())) { + AudioWaveUtils.removeFMT(audioStream); + } while (-1 != nRead) { nRead = audioStream.read(abData, 0, abData.length); if (nRead >= 0) { diff --git a/bundles/org.openhab.core.audio/src/main/java/org/openhab/core/audio/utils/AudioWaveUtils.java b/bundles/org.openhab.core.audio/src/main/java/org/openhab/core/audio/utils/AudioWaveUtils.java index c3169252ee..6db5165e5c 100644 --- a/bundles/org.openhab.core.audio/src/main/java/org/openhab/core/audio/utils/AudioWaveUtils.java +++ b/bundles/org.openhab.core.audio/src/main/java/org/openhab/core/audio/utils/AudioWaveUtils.java @@ -12,6 +12,7 @@ */ package org.openhab.core.audio.utils; +import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; @@ -31,6 +32,11 @@ import org.openhab.core.audio.AudioFormat; @NonNullByDefault public class AudioWaveUtils { + /** + * This "magic" packet marks the beginning of the read data + */ + private final static int DATA_MAGIC = 0x64617461; + private static final AudioFormat DEFAULT_WAVE_AUDIO_FORMAT = new AudioFormat(AudioFormat.CONTAINER_WAVE, AudioFormat.CODEC_PCM_SIGNED, false, 16, 705600, 44100L, 1); @@ -69,4 +75,26 @@ public class AudioWaveUtils { inputStream.reset(); } } + + /** + * Remove FMT block (WAV header) from a stream by consuming it until + * the magic packet signaling data. Limit to 200 readInt() (arbitrary value + * used in sun audio package). + * If you don't remove/consume the FMT and pass the data to a player + * as if it is a pure PCM stream, it could try to play it and will + * do a "click" noise at the beginning. + * + * @param audio A wav container in an InputStream + * @throws IOException + */ + public static void removeFMT(InputStream data) throws IOException { + DataInputStream dataInputStream = new DataInputStream(data); + Integer nextInt = dataInputStream.readInt(); + int i = 0; + while (nextInt != DATA_MAGIC && i < 200) { + nextInt = dataInputStream.readInt(); + i++; + } + dataInputStream.readInt(); + } }