[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 <gwendal.roulleau@gmail.com>
pull/2680/head
dalgwen 2022-01-10 08:56:38 +01:00 committed by GitHub
parent 0a778df0ad
commit fa029b265c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 1 deletions

View File

@ -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) {

View File

@ -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();
}
}