diff --git a/src/main/java/io/github/dsheirer/alias/action/beep/BeepAction.java b/src/main/java/io/github/dsheirer/alias/action/beep/BeepAction.java index d2e993ca..f6b6457b 100644 --- a/src/main/java/io/github/dsheirer/alias/action/beep/BeepAction.java +++ b/src/main/java/io/github/dsheirer/alias/action/beep/BeepAction.java @@ -1,7 +1,6 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2018 Dennis Sheirer + * ***************************************************************************** + * Copyright (C) 2014-2022 Dennis Sheirer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see - * ***************************************************************************** + * **************************************************************************** */ package io.github.dsheirer.alias.action.beep; @@ -72,7 +71,7 @@ public class BeepAction extends RecurringAction @Override public void performAction(Alias alias, IMessage message ) { - DataLine.Info info = new DataLine.Info(Clip.class, AudioFormats.PCM_SIGNED_8KHZ_16BITS_MONO); + DataLine.Info info = new DataLine.Info(Clip.class, AudioFormats.PCM_SIGNED_8_KHZ_16BITS_MONO); if(!AudioSystem.isLineSupported(info)) { @@ -83,7 +82,7 @@ public class BeepAction extends RecurringAction try { Clip clip = (Clip)AudioSystem.getLine(info); - clip.open(AudioFormats.PCM_SIGNED_8KHZ_16BITS_MONO, mToneBytes, 0, mToneBytes.length); + clip.open(AudioFormats.PCM_SIGNED_8_KHZ_16BITS_MONO, mToneBytes, 0, mToneBytes.length); clip.start(); } catch(Exception e) diff --git a/src/main/java/io/github/dsheirer/audio/AudioFormats.java b/src/main/java/io/github/dsheirer/audio/AudioFormats.java index c6cbed82..ea901d46 100644 --- a/src/main/java/io/github/dsheirer/audio/AudioFormats.java +++ b/src/main/java/io/github/dsheirer/audio/AudioFormats.java @@ -1,3 +1,22 @@ +/* + * ***************************************************************************** + * Copyright (C) 2014-2022 Dennis Sheirer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * **************************************************************************** + */ + package io.github.dsheirer.audio; import javax.sound.sampled.AudioFormat; @@ -15,8 +34,12 @@ public class AudioFormats public static final float IMBE_FRAME_RATE = 50; public static final float IMBE_SAMPLE_RATE = 50; - public static final float PCM_8KHZ_RATE = 8000; - public static final float PCM_48KHZ_RATE = 48000; + + public static final float PCM_8_KHZ_RATE = 8000; + public static final float PCM_16_KHZ_RATE = 16000; + public static final float PCM_22050_HZ_RATE = 22050; + public static final float PCM_44100_HZ_RATE = 44100; + public static final float PCM_48_KHZ_RATE = 48000; public static final int IMBE_FRAME_SIZE_BYTES = 18; public static final int IMBE_SAMPLE_SIZE_BITS = 144; @@ -35,47 +58,74 @@ public class AudioFormats IMBE_FRAME_RATE, LITTLE_ENDIAN ); - public static AudioFormat PCM_SIGNED_8KHZ_16BITS_MONO = - new AudioFormat( AudioFormat.Encoding.PCM_SIGNED, - PCM_8KHZ_RATE, + public static AudioFormat PCM_SIGNED_8_KHZ_16BITS_MONO = + new AudioFormat( AudioFormat.Encoding.PCM_SIGNED, + PCM_8_KHZ_RATE, PCM_SAMPLE_SIZE_BITS, ONE_CHANNEL, - PCM_FRAME_SIZE_BYTES_MONO, - PCM_8KHZ_RATE, + PCM_FRAME_SIZE_BYTES_MONO, + PCM_8_KHZ_RATE, LITTLE_ENDIAN ); + public static AudioFormat PCM_SIGNED_16_KHZ_16BITS_MONO = + new AudioFormat( AudioFormat.Encoding.PCM_SIGNED, + PCM_16_KHZ_RATE, + PCM_SAMPLE_SIZE_BITS, + ONE_CHANNEL, + PCM_FRAME_SIZE_BYTES_MONO, + PCM_16_KHZ_RATE, + LITTLE_ENDIAN ); + + public static AudioFormat PCM_SIGNED_22050_HZ_16BITS_MONO = + new AudioFormat( AudioFormat.Encoding.PCM_SIGNED, + PCM_22050_HZ_RATE, + PCM_SAMPLE_SIZE_BITS, + ONE_CHANNEL, + PCM_FRAME_SIZE_BYTES_MONO, + PCM_22050_HZ_RATE, + LITTLE_ENDIAN ); + + public static AudioFormat PCM_SIGNED_44100_HZ_16BITS_MONO = + new AudioFormat( AudioFormat.Encoding.PCM_SIGNED, + PCM_44100_HZ_RATE, + PCM_SAMPLE_SIZE_BITS, + ONE_CHANNEL, + PCM_FRAME_SIZE_BYTES_MONO, + PCM_44100_HZ_RATE, + LITTLE_ENDIAN ); + public static AudioFormat PCM_SIGNED_8KHZ_16BITS_STEREO = new AudioFormat( AudioFormat.Encoding.PCM_SIGNED, - PCM_8KHZ_RATE, + PCM_8_KHZ_RATE, PCM_SAMPLE_SIZE_BITS, TWO_CHANNELS, PCM_FRAME_SIZE_BYTES_STEREO, - PCM_8KHZ_RATE, + PCM_8_KHZ_RATE, LITTLE_ENDIAN ); public static AudioFormat PCM_SIGNED_48KHZ_16BITS_MONO = - new AudioFormat( AudioFormat.Encoding.PCM_SIGNED, - PCM_48KHZ_RATE, + new AudioFormat( AudioFormat.Encoding.PCM_SIGNED, + PCM_48_KHZ_RATE, PCM_SAMPLE_SIZE_BITS, ONE_CHANNEL, - PCM_FRAME_SIZE_BYTES_MONO, - PCM_48KHZ_RATE, + PCM_FRAME_SIZE_BYTES_MONO, + PCM_48_KHZ_RATE, LITTLE_ENDIAN ); public static AudioFormat PCM_SIGNED_48KHZ_16BITS_STEREO = - new AudioFormat( AudioFormat.Encoding.PCM_SIGNED, - PCM_48KHZ_RATE, + new AudioFormat( AudioFormat.Encoding.PCM_SIGNED, + PCM_48_KHZ_RATE, PCM_SAMPLE_SIZE_BITS, TWO_CHANNELS, - PCM_FRAME_SIZE_BYTES_STEREO, - PCM_48KHZ_RATE, + PCM_FRAME_SIZE_BYTES_STEREO, + PCM_48_KHZ_RATE, LITTLE_ENDIAN ); /** * Source Data Line Info for a 48 kHz, 16-bits signed PCM one channel */ public static final Line.Info MONO_SOURCE_DATALINE_INFO = - new DataLine.Info( SourceDataLine.class, PCM_SIGNED_8KHZ_16BITS_MONO); + new DataLine.Info( SourceDataLine.class, PCM_SIGNED_8_KHZ_16BITS_MONO); /** * Source Data Line Info for a 48 kHz, 16-bits signed PCM two channels diff --git a/src/main/java/io/github/dsheirer/audio/AudioUtils.java b/src/main/java/io/github/dsheirer/audio/AudioUtils.java index a42f6784..0f0dd223 100644 --- a/src/main/java/io/github/dsheirer/audio/AudioUtils.java +++ b/src/main/java/io/github/dsheirer/audio/AudioUtils.java @@ -1,18 +1,21 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 Dennis Sheirer +/* + * ***************************************************************************** + * Copyright (C) 2014-2022 Dennis Sheirer * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along with this program. - * If not, see - * - ******************************************************************************/ + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * **************************************************************************** + */ package io.github.dsheirer.audio; import io.github.dsheirer.sample.ConversionUtils; @@ -75,5 +78,4 @@ public class AudioUtils return stream.toByteArray(); } - } diff --git a/src/main/java/io/github/dsheirer/audio/broadcast/AudioStreamingBroadcaster.java b/src/main/java/io/github/dsheirer/audio/broadcast/AudioStreamingBroadcaster.java index 05641152..289d22e3 100644 --- a/src/main/java/io/github/dsheirer/audio/broadcast/AudioStreamingBroadcaster.java +++ b/src/main/java/io/github/dsheirer/audio/broadcast/AudioStreamingBroadcaster.java @@ -1,27 +1,26 @@ /* + * ***************************************************************************** + * Copyright (C) 2014-2022 Dennis Sheirer * - * * ****************************************************************************** - * * Copyright (C) 2014-2020 Dennis Sheirer - * * - * * This program is free software: you can redistribute it and/or modify - * * it under the terms of the GNU General Public License as published by - * * the Free Software Foundation, either version 3 of the License, or - * * (at your option) any later version. - * * - * * This program is distributed in the hope that it will be useful, - * * but WITHOUT ANY WARRANTY; without even the implied warranty of - * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * * GNU General Public License for more details. - * * - * * You should have received a copy of the GNU General Public License - * * along with this program. If not, see - * * ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * **************************************************************************** */ package io.github.dsheirer.audio.broadcast; +import io.github.dsheirer.audio.convert.AudioSampleRate; import io.github.dsheirer.audio.convert.ISilenceGenerator; +import io.github.dsheirer.audio.convert.MP3Setting; import io.github.dsheirer.identifier.IdentifierCollection; import io.github.dsheirer.util.ThreadPool; import org.apache.commons.math3.util.FastMath; @@ -31,6 +30,7 @@ import org.slf4j.LoggerFactory; import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.file.Files; +import java.util.List; import java.util.Queue; import java.util.concurrent.LinkedTransferQueue; import java.util.concurrent.ScheduledFuture; @@ -73,12 +73,13 @@ public abstract class AudioStreamingBroadcaster 0) { - broadcastAudio(mSilenceGenerator.generate(mFinalSilencePadding)); + List finalSilence = mSilenceGenerator.generate(mFinalSilencePadding); + + for(byte[] silence: finalSilence) + { + broadcastAudio(silence); + } + mFinalSilencePadding = 0; } @@ -312,7 +319,11 @@ public abstract class AudioStreamingBroadcaster silenceFrames = mSilenceGenerator.generate(PROCESSOR_RUN_INTERVAL_MS); + for(byte[] silence: silenceFrames) + { + broadcastAudio(silence); + } } } catch(Throwable t) diff --git a/src/main/java/io/github/dsheirer/audio/broadcast/AudioStreamingManager.java b/src/main/java/io/github/dsheirer/audio/broadcast/AudioStreamingManager.java index 352860ac..864d30e9 100644 --- a/src/main/java/io/github/dsheirer/audio/broadcast/AudioStreamingManager.java +++ b/src/main/java/io/github/dsheirer/audio/broadcast/AudioStreamingManager.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2020 Dennis Sheirer + * Copyright (C) 2014-2022 Dennis Sheirer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -150,7 +150,7 @@ public class AudioStreamingManager implements Listener try { - AudioSegmentRecorder.record(audioSegment, path, RecordFormat.MP3); + AudioSegmentRecorder.record(audioSegment, path, RecordFormat.MP3, mUserPreferences); IdentifierCollection identifierCollectionCopy = new IdentifierCollection(audioSegment.getIdentifierCollection().getIdentifiers()); diff --git a/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastFactory.java b/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastFactory.java index ad663354..f584d8d7 100644 --- a/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastFactory.java +++ b/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastFactory.java @@ -1,23 +1,20 @@ /* + * ***************************************************************************** + * Copyright (C) 2014-2022 Dennis Sheirer * - * * ****************************************************************************** - * * Copyright (C) 2014-2019 Dennis Sheirer - * * - * * This program is free software: you can redistribute it and/or modify - * * it under the terms of the GNU General Public License as published by - * * the Free Software Foundation, either version 3 of the License, or - * * (at your option) any later version. - * * - * * This program is distributed in the hope that it will be useful, - * * but WITHOUT ANY WARRANTY; without even the implied warranty of - * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * * GNU General Public License for more details. - * * - * * You should have received a copy of the GNU General Public License - * * along with this program. If not, see - * * ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * **************************************************************************** */ package io.github.dsheirer.audio.broadcast; @@ -33,10 +30,13 @@ import io.github.dsheirer.audio.broadcast.shoutcast.v1.ShoutcastV1AudioBroadcast import io.github.dsheirer.audio.broadcast.shoutcast.v1.ShoutcastV1Configuration; import io.github.dsheirer.audio.broadcast.shoutcast.v2.ShoutcastV2AudioStreamingBroadcaster; import io.github.dsheirer.audio.broadcast.shoutcast.v2.ShoutcastV2Configuration; +import io.github.dsheirer.audio.convert.AudioSampleRate; import io.github.dsheirer.audio.convert.IAudioConverter; import io.github.dsheirer.audio.convert.ISilenceGenerator; import io.github.dsheirer.audio.convert.MP3AudioConverter; +import io.github.dsheirer.audio.convert.MP3Setting; import io.github.dsheirer.audio.convert.MP3SilenceGenerator; +import io.github.dsheirer.preference.UserPreferences; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,42 +44,44 @@ public class BroadcastFactory { private final static Logger mLog = LoggerFactory.getLogger(BroadcastFactory.class); - public static final int MP3_MONO_16_KHZ_BITRATE = 16; - public static final boolean MP3_CONSTANT_BITRATE = false; - /** * Creates an audio streaming broadcaster for the configuration * * @param configuration describing the server and audio types * @return configured broadcaster or null */ - public static AbstractAudioBroadcaster getBroadcaster(BroadcastConfiguration configuration, AliasModel aliasModel) + public static AbstractAudioBroadcaster getBroadcaster(BroadcastConfiguration configuration, AliasModel aliasModel, + UserPreferences userPreferences) { if(configuration != null) { - IAudioConverter converter = getAudioConverter(configuration); + AudioSampleRate audioSampleRate = userPreferences.getMP3Preference().getAudioSampleRate(); + MP3Setting mp3Setting = userPreferences.getMP3Preference().getMP3Setting(); - if(converter != null) + switch(configuration.getBroadcastServerType()) { - switch(configuration.getBroadcastServerType()) - { - case BROADCASTIFY_CALL: - return new BroadcastifyCallBroadcaster((BroadcastifyCallConfiguration)configuration, aliasModel); - case BROADCASTIFY: - return new IcecastTCPAudioBroadcaster((BroadcastifyFeedConfiguration) configuration, aliasModel); - case ICECAST_TCP: - return new IcecastTCPAudioBroadcaster((IcecastTCPConfiguration) configuration, aliasModel); - case ICECAST_HTTP: - return new IcecastHTTPAudioBroadcaster((IcecastHTTPConfiguration) configuration, aliasModel); - case SHOUTCAST_V1: - return new ShoutcastV1AudioBroadcaster((ShoutcastV1Configuration) configuration, aliasModel); - case SHOUTCAST_V2: - return new ShoutcastV2AudioStreamingBroadcaster((ShoutcastV2Configuration) configuration, aliasModel); - case UNKNOWN: - default: - mLog.info("Unrecognized broadcastAudio configuration: " + configuration.getBroadcastFormat().name()); - break; - } + case BROADCASTIFY_CALL: + return new BroadcastifyCallBroadcaster((BroadcastifyCallConfiguration)configuration, + audioSampleRate, mp3Setting, aliasModel); + case BROADCASTIFY: + return new IcecastTCPAudioBroadcaster((BroadcastifyFeedConfiguration) configuration, + audioSampleRate, mp3Setting, aliasModel); + case ICECAST_TCP: + return new IcecastTCPAudioBroadcaster((IcecastTCPConfiguration) configuration, audioSampleRate, + mp3Setting, aliasModel); + case ICECAST_HTTP: + return new IcecastHTTPAudioBroadcaster((IcecastHTTPConfiguration) configuration, audioSampleRate, + mp3Setting, aliasModel); + case SHOUTCAST_V1: + return new ShoutcastV1AudioBroadcaster((ShoutcastV1Configuration) configuration, audioSampleRate, + mp3Setting, aliasModel); + case SHOUTCAST_V2: + return new ShoutcastV2AudioStreamingBroadcaster((ShoutcastV2Configuration) configuration, + audioSampleRate, mp3Setting, aliasModel); + case UNKNOWN: + default: + mLog.info("Unrecognized broadcastAudio configuration: " + configuration.getBroadcastFormat().name()); + break; } } @@ -92,12 +94,13 @@ public class BroadcastFactory * @param configuration containing the requested output audio format * @return audio convert or null */ - public static IAudioConverter getAudioConverter(BroadcastConfiguration configuration) + public static IAudioConverter getAudioConverter(BroadcastConfiguration configuration, AudioSampleRate audioSampleRate, + MP3Setting mp3Setting) { switch(configuration.getBroadcastFormat()) { case MP3: - return new MP3AudioConverter(MP3_MONO_16_KHZ_BITRATE, MP3_CONSTANT_BITRATE); + return new MP3AudioConverter(audioSampleRate, mp3Setting); default: mLog.info("Unrecognized broadcastAudio format: " + configuration.getBroadcastFormat().name()); } @@ -137,12 +140,12 @@ public class BroadcastFactory return null; } - public static ISilenceGenerator getSilenceGenerator(BroadcastFormat format) + public static ISilenceGenerator getSilenceGenerator(BroadcastFormat format, AudioSampleRate audioSampleRate, MP3Setting mp3Setting) { switch(format) { case MP3: - return new MP3SilenceGenerator(); + return new MP3SilenceGenerator(audioSampleRate, mp3Setting); default: throw new IllegalArgumentException("Unrecognized broadcast format [" + format + "] can't create silence generator"); diff --git a/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastModel.java b/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastModel.java index c04d9665..025042e4 100644 --- a/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastModel.java +++ b/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastModel.java @@ -1,23 +1,20 @@ /* + * ***************************************************************************** + * Copyright (C) 2014-2022 Dennis Sheirer * - * * ****************************************************************************** - * * Copyright (C) 2014-2020 Dennis Sheirer - * * - * * This program is free software: you can redistribute it and/or modify - * * it under the terms of the GNU General Public License as published by - * * the Free Software Foundation, either version 3 of the License, or - * * (at your option) any later version. - * * - * * This program is distributed in the hope that it will be useful, - * * but WITHOUT ANY WARRANTY; without even the implied warranty of - * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * * GNU General Public License for more details. - * * - * * You should have received a copy of the GNU General Public License - * * along with this program. If not, see - * * ***************************************************************************** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * **************************************************************************** */ package io.github.dsheirer.audio.broadcast; @@ -34,7 +31,7 @@ import javafx.collections.ObservableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.swing.ImageIcon; +import javax.swing.*; import javax.swing.table.AbstractTableModel; import java.io.IOException; import java.nio.file.DirectoryStream; @@ -80,6 +77,7 @@ public class BroadcastModel extends AbstractTableModel implements Listener