mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-15 01:57:39 -05:00
#30 WIP - icecast 2 broadcaster cleanup
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -92,6 +92,22 @@ public abstract class AudioBroadcaster implements IAudioPacketListener
|
|||||||
SystemProperties.getInstance().getApplicationFolder(BroadcastModel.TEMPORARY_STREAM_DIRECTORY));
|
SystemProperties.getInstance().getApplicationFolder(BroadcastModel.TEMPORARY_STREAM_DIRECTORY));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast binary audio data frames or sequences.
|
||||||
|
*/
|
||||||
|
protected abstract void broadcastAudio(byte[] audio);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcasts the next song's audio metadata prior to streaming the next song.
|
||||||
|
* @param metadata
|
||||||
|
*/
|
||||||
|
protected abstract void broadcastMetadata(AudioMetadata metadata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnects the broadcaster from the remote server for a reset or final stop.
|
||||||
|
*/
|
||||||
|
protected abstract void disconnect();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connects to the remote server specified by the broadcast configuration and starts audio streaming.
|
* Connects to the remote server specified by the broadcast configuration and starts audio streaming.
|
||||||
*/
|
*/
|
||||||
@@ -130,11 +146,6 @@ public abstract class AudioBroadcaster implements IAudioPacketListener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Disconnects the broadcaster from the remote server for a reset or final stop.
|
|
||||||
*/
|
|
||||||
protected abstract void disconnect();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of recording queue for recordings awaiting streaming
|
* Size of recording queue for recordings awaiting streaming
|
||||||
*/
|
*/
|
||||||
@@ -197,18 +208,7 @@ public abstract class AudioBroadcaster implements IAudioPacketListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcast binary audio data frames or sequences.
|
* Registers the listener to receive broadcast events/state changes
|
||||||
*/
|
|
||||||
protected abstract void broadcastAudio(byte[] audio);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Broadcasts the next song's audio metadata prior to streaming the next song.
|
|
||||||
* @param metadata
|
|
||||||
*/
|
|
||||||
protected abstract void broadcastMetadata(AudioMetadata metadata);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers the listener to receive broadcastAudio state changes
|
|
||||||
*/
|
*/
|
||||||
public void setListener(Listener<BroadcastEvent> listener)
|
public void setListener(Listener<BroadcastEvent> listener)
|
||||||
{
|
{
|
||||||
@@ -216,7 +216,7 @@ public abstract class AudioBroadcaster implements IAudioPacketListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the listener from receiving broadcastAudio state changes
|
* Removes the listener from receiving broadcast events/state changes
|
||||||
*/
|
*/
|
||||||
public void removeListener()
|
public void removeListener()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,17 +18,24 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package audio.broadcast;
|
package audio.broadcast;
|
||||||
|
|
||||||
|
import audio.broadcast.broadcastify.BroadcastifyConfiguration;
|
||||||
|
import audio.broadcast.icecast.IcecastHTTPConfiguration;
|
||||||
import audio.broadcast.icecast.IcecastTCPConfiguration;
|
import audio.broadcast.icecast.IcecastTCPConfiguration;
|
||||||
|
import audio.broadcast.shoutcast.v1.ShoutcastV1Configuration;
|
||||||
|
import audio.broadcast.shoutcast.v2.ShoutcastV2Configuration;
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlAttribute;
|
import javax.xml.bind.annotation.XmlAttribute;
|
||||||
import javax.xml.bind.annotation.XmlElement;
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||||
import javax.xml.bind.annotation.XmlTransient;
|
import javax.xml.bind.annotation.XmlTransient;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
|
|
||||||
@XmlSeeAlso({IcecastTCPConfiguration.class})
|
@XmlSeeAlso({BroadcastifyConfiguration.class,
|
||||||
|
IcecastTCPConfiguration.class,
|
||||||
|
IcecastHTTPConfiguration.class,
|
||||||
|
ShoutcastV1Configuration.class,
|
||||||
|
ShoutcastV2Configuration.class})
|
||||||
@XmlRootElement(name = "stream")
|
@XmlRootElement(name = "stream")
|
||||||
public abstract class BroadcastConfiguration
|
public abstract class BroadcastConfiguration
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import audio.broadcast.broadcastify.BroadcastifyConfiguration;
|
|||||||
import audio.broadcast.broadcastify.BroadcastifyConfigurationEditor;
|
import audio.broadcast.broadcastify.BroadcastifyConfigurationEditor;
|
||||||
import audio.broadcast.icecast.IcecastHTTPAudioBroadcaster;
|
import audio.broadcast.icecast.IcecastHTTPAudioBroadcaster;
|
||||||
import audio.broadcast.icecast.IcecastHTTPConfiguration;
|
import audio.broadcast.icecast.IcecastHTTPConfiguration;
|
||||||
|
import audio.broadcast.icecast.IcecastHTTPConfigurationEditor;
|
||||||
import audio.broadcast.icecast.IcecastTCPAudioBroadcaster;
|
import audio.broadcast.icecast.IcecastTCPAudioBroadcaster;
|
||||||
import audio.broadcast.icecast.IcecastTCPConfiguration;
|
import audio.broadcast.icecast.IcecastTCPConfiguration;
|
||||||
import audio.broadcast.icecast.IcecastTCPConfigurationEditor;
|
import audio.broadcast.icecast.IcecastTCPConfigurationEditor;
|
||||||
@@ -75,12 +76,13 @@ public class BroadcastFactory
|
|||||||
{
|
{
|
||||||
case BROADCASTIFY:
|
case BROADCASTIFY:
|
||||||
return new IcecastTCPAudioBroadcaster(defaultAsyncHttpClient, threadPoolManager,
|
return new IcecastTCPAudioBroadcaster(defaultAsyncHttpClient, threadPoolManager,
|
||||||
(BroadcastifyConfiguration)configuration);
|
(BroadcastifyConfiguration)configuration);
|
||||||
case ICECAST_TCP:
|
case ICECAST_TCP:
|
||||||
return new IcecastTCPAudioBroadcaster(defaultAsyncHttpClient, threadPoolManager,
|
return new IcecastTCPAudioBroadcaster(defaultAsyncHttpClient, threadPoolManager,
|
||||||
(IcecastTCPConfiguration)configuration);
|
(IcecastTCPConfiguration)configuration);
|
||||||
case ICECAST_HTTP:
|
case ICECAST_HTTP:
|
||||||
return new IcecastHTTPAudioBroadcaster(threadPoolManager, (IcecastHTTPConfiguration)configuration);
|
return new IcecastHTTPAudioBroadcaster(defaultAsyncHttpClient, threadPoolManager,
|
||||||
|
(IcecastHTTPConfiguration)configuration);
|
||||||
case SHOUTCAST_V1:
|
case SHOUTCAST_V1:
|
||||||
return new ShoutcastV1AudioBroadcaster(threadPoolManager, (ShoutcastV1Configuration)configuration);
|
return new ShoutcastV1AudioBroadcaster(threadPoolManager, (ShoutcastV1Configuration)configuration);
|
||||||
case SHOUTCAST_V2:
|
case SHOUTCAST_V2:
|
||||||
@@ -165,6 +167,9 @@ public class BroadcastFactory
|
|||||||
case ICECAST_TCP:
|
case ICECAST_TCP:
|
||||||
editor = new IcecastTCPConfigurationEditor(broadcastModel, aliasModel, settingsManager);
|
editor = new IcecastTCPConfigurationEditor(broadcastModel, aliasModel, settingsManager);
|
||||||
break;
|
break;
|
||||||
|
case ICECAST_HTTP:
|
||||||
|
editor = new IcecastHTTPConfigurationEditor(broadcastModel, aliasModel, settingsManager);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
editor = new EmptyEditor<BroadcastConfiguration>();
|
editor = new EmptyEditor<BroadcastConfiguration>();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -242,26 +242,18 @@ public class BroadcastModel extends AbstractTableModel implements Listener<Audio
|
|||||||
|
|
||||||
public void removeBroadcastConfiguration(BroadcastConfiguration broadcastConfiguration)
|
public void removeBroadcastConfiguration(BroadcastConfiguration broadcastConfiguration)
|
||||||
{
|
{
|
||||||
mLog.debug("Removing broadcast configuration: " + broadcastConfiguration.getName());
|
|
||||||
if(broadcastConfiguration != null && mBroadcastConfigurations.contains(broadcastConfiguration))
|
if(broadcastConfiguration != null && mBroadcastConfigurations.contains(broadcastConfiguration))
|
||||||
{
|
{
|
||||||
int index = mBroadcastConfigurations.indexOf(broadcastConfiguration);
|
int index = mBroadcastConfigurations.indexOf(broadcastConfiguration);
|
||||||
|
|
||||||
mLog.debug("Removing configuration. Index was:" + index);
|
|
||||||
mBroadcastConfigurations.remove(broadcastConfiguration);
|
mBroadcastConfigurations.remove(broadcastConfiguration);
|
||||||
|
|
||||||
mLog.debug("Removing configuration from map. Index was:" + index);
|
|
||||||
mBroadcastConfigurationMap.remove(broadcastConfiguration.getName());
|
mBroadcastConfigurationMap.remove(broadcastConfiguration.getName());
|
||||||
|
|
||||||
mLog.debug("Broadcasting config delete event");
|
|
||||||
process(new BroadcastEvent( broadcastConfiguration, BroadcastEvent.Event.CONFIGURATION_DELETE));
|
process(new BroadcastEvent( broadcastConfiguration, BroadcastEvent.Event.CONFIGURATION_DELETE));
|
||||||
|
|
||||||
fireTableRowsDeleted( index, index );
|
fireTableRowsDeleted( index, index );
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
mLog.debug("Config was null or not in the broadcaast configs list");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -339,12 +331,10 @@ public class BroadcastModel extends AbstractTableModel implements Listener<Audio
|
|||||||
*/
|
*/
|
||||||
private void deleteBroadcaster(String name)
|
private void deleteBroadcaster(String name)
|
||||||
{
|
{
|
||||||
mLog.debug("Deleting broadcaster: " + name);
|
|
||||||
if(name != null && mBroadcasterMap.containsKey(name))
|
if(name != null && mBroadcasterMap.containsKey(name))
|
||||||
{
|
{
|
||||||
AudioBroadcaster audioBroadcaster = mBroadcasterMap.remove(name);
|
AudioBroadcaster audioBroadcaster = mBroadcasterMap.remove(name);
|
||||||
|
|
||||||
mLog.debug("Found the broadcaster: " + (audioBroadcaster != null));
|
|
||||||
if(audioBroadcaster != null)
|
if(audioBroadcaster != null)
|
||||||
{
|
{
|
||||||
audioBroadcaster.stop();
|
audioBroadcaster.stop();
|
||||||
@@ -360,9 +350,12 @@ public class BroadcastModel extends AbstractTableModel implements Listener<Audio
|
|||||||
broadcast(new BroadcastEvent(audioBroadcaster, BroadcastEvent.Event.BROADCASTER_DELETE));
|
broadcast(new BroadcastEvent(audioBroadcaster, BroadcastEvent.Event.BROADCASTER_DELETE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mLog.debug("Finished deleting broadcaster: " + name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP client shared across all broadcaster instances. Note: client is lazy construct so that it isn't
|
||||||
|
* created until required
|
||||||
|
*/
|
||||||
private DefaultAsyncHttpClient getDefaultAsyncHttpClient()
|
private DefaultAsyncHttpClient getDefaultAsyncHttpClient()
|
||||||
{
|
{
|
||||||
if (mDefaultAsyncHttpClient == null)
|
if (mDefaultAsyncHttpClient == null)
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ public class BroadcastPanel extends JPanel implements ActionListener, ListSelect
|
|||||||
|
|
||||||
menu.add(new AddBroadcastConfigurationItem(BroadcastServerType.BROADCASTIFY));
|
menu.add(new AddBroadcastConfigurationItem(BroadcastServerType.BROADCASTIFY));
|
||||||
menu.add(new AddBroadcastConfigurationItem(BroadcastServerType.ICECAST_TCP));
|
menu.add(new AddBroadcastConfigurationItem(BroadcastServerType.ICECAST_TCP));
|
||||||
|
menu.add(new AddBroadcastConfigurationItem(BroadcastServerType.ICECAST_HTTP));
|
||||||
|
|
||||||
menu.show(e.getComponent(), e.getX(), e.getY());
|
menu.show(e.getComponent(), e.getX(), e.getY());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ package audio.broadcast;
|
|||||||
public enum BroadcastServerType
|
public enum BroadcastServerType
|
||||||
{
|
{
|
||||||
BROADCASTIFY("Broadcastify", "images/broadcastify.png"), //Icecast Server 2.3.2
|
BROADCASTIFY("Broadcastify", "images/broadcastify.png"), //Icecast Server 2.3.2
|
||||||
ICECAST_HTTP("Icecast 2.4+", "images/icecast.png"),
|
ICECAST_HTTP("Icecast 2 (v2.4+)", "images/icecast.png"),
|
||||||
ICECAST_TCP("Icecast 2.3", "images/icecast.png"),
|
ICECAST_TCP("Icecast (v2.3)", "images/icecast.png"),
|
||||||
SHOUTCAST_V1("Shoutcast 1.x", "images/shoutcast.png"),
|
SHOUTCAST_V1("Shoutcast v1.x", "images/shoutcast.png"),
|
||||||
SHOUTCAST_V2("Shoutcast 2.x", "images/shoutcast.png"),
|
SHOUTCAST_V2("Shoutcast v2.x", "images/shoutcast.png"),
|
||||||
UNKNOWN("Unknown", null);
|
UNKNOWN("Unknown", null);
|
||||||
|
|
||||||
private String mLabel;
|
private String mLabel;
|
||||||
|
|||||||
@@ -20,9 +20,7 @@ package audio.broadcast.icecast;
|
|||||||
|
|
||||||
import audio.AudioPacket;
|
import audio.AudioPacket;
|
||||||
import audio.broadcast.AudioBroadcaster;
|
import audio.broadcast.AudioBroadcaster;
|
||||||
import audio.broadcast.BroadcastFormat;
|
|
||||||
import audio.broadcast.BroadcastState;
|
import audio.broadcast.BroadcastState;
|
||||||
import audio.broadcast.BroadcastFactory;
|
|
||||||
import audio.metadata.AudioMetadata;
|
import audio.metadata.AudioMetadata;
|
||||||
import controller.ThreadPoolManager;
|
import controller.ThreadPoolManager;
|
||||||
import org.asynchttpclient.AsyncHandler;
|
import org.asynchttpclient.AsyncHandler;
|
||||||
@@ -42,12 +40,8 @@ import org.reactivestreams.Subscription;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import properties.SystemProperties;
|
import properties.SystemProperties;
|
||||||
import record.wave.AudioPacketMonoWaveReader;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
@@ -60,22 +54,27 @@ public class IcecastHTTPAudioBroadcaster extends AudioBroadcaster implements Pub
|
|||||||
private static final String HTTP_100_CONTINUE = "100-continue";
|
private static final String HTTP_100_CONTINUE = "100-continue";
|
||||||
private static final long RECONNECT_INTERVAL_MILLISECONDS = 15000; //15 seconds
|
private static final long RECONNECT_INTERVAL_MILLISECONDS = 15000; //15 seconds
|
||||||
private long mLastConnectionAttempt = 0;
|
private long mLastConnectionAttempt = 0;
|
||||||
private DefaultAsyncHttpClient mAsyncHttpClient;
|
private DefaultAsyncHttpClient mDefaultAsyncHttpClient;
|
||||||
private Subscriber<? super ByteBuffer> mSubscriber;
|
private Subscriber<? super ByteBuffer> mSubscriber;
|
||||||
private List<AudioPacket> mPacketsToBroadcast = new ArrayList<>();
|
private List<AudioPacket> mPacketsToBroadcast = new ArrayList<>();
|
||||||
private ConvertedAudioStreamSubscription mSubscription;
|
private ConvertedAudioStreamSubscription mSubscription;
|
||||||
private AtomicBoolean mConnecting = new AtomicBoolean();
|
private AtomicBoolean mConnecting = new AtomicBoolean();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an Icecast 2.4.x (or newer) compatible broadcaster using HTTP 1.1 protocol
|
* Creates an Icecast 2 (v2.4.x or newer) compatible broadcaster using HTTP 1.1 protocol
|
||||||
*
|
*
|
||||||
* Note: use @see IcecastTCPAudioBroadcaster for Icecast version 2.3.x and older.
|
* Note: use @see IcecastTCPAudioBroadcaster for Icecast 1 (v2.3.x and older).
|
||||||
* @param configuration
|
*
|
||||||
* @param audioConverter
|
* @param defaultAsyncHttpClient to use when communicating with a remote HTTP server
|
||||||
|
* @param threadPoolManager
|
||||||
|
* @param configuration to use when connecting to the remote server
|
||||||
*/
|
*/
|
||||||
public IcecastHTTPAudioBroadcaster(ThreadPoolManager threadPoolManager, IcecastHTTPConfiguration configuration)
|
public IcecastHTTPAudioBroadcaster(DefaultAsyncHttpClient defaultAsyncHttpClient,
|
||||||
|
ThreadPoolManager threadPoolManager,
|
||||||
|
IcecastHTTPConfiguration configuration)
|
||||||
{
|
{
|
||||||
super(threadPoolManager, configuration);
|
super(threadPoolManager, configuration);
|
||||||
|
mDefaultAsyncHttpClient = defaultAsyncHttpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -94,7 +93,7 @@ public class IcecastHTTPAudioBroadcaster extends AudioBroadcaster implements Pub
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcast any queued audio packets using Icecast V2 Protocol
|
* Broadcast converted audio chunks received from the parent class processor
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void broadcastAudio(byte[] audio)
|
protected void broadcastAudio(byte[] audio)
|
||||||
@@ -147,7 +146,7 @@ public class IcecastHTTPAudioBroadcaster extends AudioBroadcaster implements Pub
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a connnection to the remote server using the shoutcast configuration information. Once disconnected
|
* Creates a connection to the remote server using the shoutcast configuration information. Once disconnected
|
||||||
* following a successful connection, attempts to reestablish a connection on a set interval
|
* following a successful connection, attempts to reestablish a connection on a set interval
|
||||||
*/
|
*/
|
||||||
private void createConnection()
|
private void createConnection()
|
||||||
@@ -159,26 +158,21 @@ public class IcecastHTTPAudioBroadcaster extends AudioBroadcaster implements Pub
|
|||||||
mLog.debug("Creating a connection to icecast server");
|
mLog.debug("Creating a connection to icecast server");
|
||||||
mLastConnectionAttempt = System.currentTimeMillis();
|
mLastConnectionAttempt = System.currentTimeMillis();
|
||||||
|
|
||||||
DefaultAsyncHttpClientConfig config = new DefaultAsyncHttpClientConfig.Builder()
|
|
||||||
.setReadTimeout(-1)
|
|
||||||
.setRequestTimeout(-1)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
mAsyncHttpClient = new DefaultAsyncHttpClient(config);
|
|
||||||
|
|
||||||
Uri uri = new Uri(Uri.HTTP, null, getConfiguration().getHost(), getConfiguration().getPort(),
|
Uri uri = new Uri(Uri.HTTP, null, getConfiguration().getHost(), getConfiguration().getPort(),
|
||||||
getConfiguration().getMountPoint(), null);
|
getConfiguration().getMountPoint(), null);
|
||||||
|
|
||||||
mLog.debug("URL:" + uri.toUrl());
|
mLog.debug("URL:" + uri.toUrl());
|
||||||
|
|
||||||
BoundRequestBuilder builder = mAsyncHttpClient.preparePut(uri.toUrl());
|
BoundRequestBuilder builder = mDefaultAsyncHttpClient.preparePut(uri.toUrl());
|
||||||
|
|
||||||
|
mLog.debug("Setting security realm");
|
||||||
//Use Basic (base64) authentication
|
//Use Basic (base64) authentication
|
||||||
Realm realm = new Realm.Builder(getConfiguration().getUserName(), getConfiguration().getPassword())
|
Realm realm = new Realm.Builder(getConfiguration().getUserName(), getConfiguration().getPassword())
|
||||||
.setScheme(Realm.AuthScheme.BASIC).setUsePreemptiveAuth(true).build();
|
.setScheme(Realm.AuthScheme.BASIC).setUsePreemptiveAuth(true).build();
|
||||||
builder.setRealm(realm);
|
builder.setRealm(realm);
|
||||||
builder.setBody(this);
|
builder.setBody(this);
|
||||||
|
|
||||||
|
mLog.debug("Adding headers");
|
||||||
builder.addHeader(IcecastHeader.ACCEPT.getValue(), "*/*");
|
builder.addHeader(IcecastHeader.ACCEPT.getValue(), "*/*");
|
||||||
builder.addHeader(IcecastHeader.CONTENT_TYPE.getValue(), getConfiguration().getBroadcastFormat().getValue());
|
builder.addHeader(IcecastHeader.CONTENT_TYPE.getValue(), getConfiguration().getBroadcastFormat().getValue());
|
||||||
builder.addHeader(IcecastHeader.PUBLIC.getValue(), getConfiguration().isPublic() ? "1" : "0");
|
builder.addHeader(IcecastHeader.PUBLIC.getValue(), getConfiguration().isPublic() ? "1" : "0");
|
||||||
@@ -214,6 +208,8 @@ public class IcecastHTTPAudioBroadcaster extends AudioBroadcaster implements Pub
|
|||||||
|
|
||||||
builder.addHeader(IcecastHeader.EXPECT.getValue(), HTTP_100_CONTINUE);
|
builder.addHeader(IcecastHeader.EXPECT.getValue(), HTTP_100_CONTINUE);
|
||||||
|
|
||||||
|
mLog.debug("executing connection with http client");
|
||||||
|
|
||||||
ListenableFuture<Response> future = builder.execute(new AsyncHttpConnectionResponseHandler());
|
ListenableFuture<Response> future = builder.execute(new AsyncHttpConnectionResponseHandler());
|
||||||
|
|
||||||
mLog.debug("Create connection was submitted asynchronously");
|
mLog.debug("Create connection was submitted asynchronously");
|
||||||
@@ -383,57 +379,4 @@ public class IcecastHTTPAudioBroadcaster extends AudioBroadcaster implements Pub
|
|||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args)
|
|
||||||
{
|
|
||||||
boolean test = false;
|
|
||||||
|
|
||||||
IcecastHTTPConfiguration config = new IcecastHTTPConfiguration(BroadcastFormat.MP3);
|
|
||||||
|
|
||||||
config.setName("Broadcastify SDRTrunk Test #2");
|
|
||||||
config.setHost("audio3.broadcastify.com");
|
|
||||||
config.setPort(80);
|
|
||||||
config.setMountPoint("/k0yrdpx7zn4h");
|
|
||||||
config.setUserName("source");
|
|
||||||
config.setPassword("k8j9405n");
|
|
||||||
config.setDescription("SDRTrunk Test Feed #2");
|
|
||||||
config.setGenre("Scanner");
|
|
||||||
config.setPublic(true);
|
|
||||||
config.setURL("http://www.radioreference.com");
|
|
||||||
config.setBitRate(16);
|
|
||||||
|
|
||||||
if(test)
|
|
||||||
{
|
|
||||||
mLog.debug("Auth:" + config.getEncodedCredentials());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ThreadPoolManager threadPoolManager = new ThreadPoolManager();
|
|
||||||
DefaultAsyncHttpClient httpClient = new DefaultAsyncHttpClient();
|
|
||||||
|
|
||||||
final AudioBroadcaster audioBroadcaster = BroadcastFactory.getBroadcaster(httpClient, threadPoolManager,config);
|
|
||||||
|
|
||||||
Path path = Paths.get("/home/denny/Music/PCM.wav");
|
|
||||||
mLog.debug("Opening: " + path.toString());
|
|
||||||
|
|
||||||
mLog.debug("Registering and starting audio playback");
|
|
||||||
|
|
||||||
while(true)
|
|
||||||
{
|
|
||||||
mLog.debug("Playback started [" + path.toString() + "]");
|
|
||||||
|
|
||||||
try (AudioPacketMonoWaveReader reader = new AudioPacketMonoWaveReader(path, true))
|
|
||||||
{
|
|
||||||
reader.setListener(audioBroadcaster);
|
|
||||||
reader.read();
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
mLog.error("Error", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
mLog.debug("Playback ended [" + path.toString() + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,12 +26,12 @@ import java.util.Base64;
|
|||||||
|
|
||||||
public class IcecastHTTPConfiguration extends BroadcastConfiguration
|
public class IcecastHTTPConfiguration extends BroadcastConfiguration
|
||||||
{
|
{
|
||||||
private String mUserName;
|
private String mUserName = "source";
|
||||||
private String mMountPoint;
|
private String mMountPoint = "stream";
|
||||||
private String mDescription;
|
private String mDescription;
|
||||||
private String mGenre;
|
private String mGenre;
|
||||||
private boolean mPublic;
|
private boolean mPublic;
|
||||||
private int mBitRate;
|
private int mBitRate = 16; //kHz
|
||||||
private int mChannels = 1;
|
private int mChannels = 1;
|
||||||
private int mSampleRate = 8000;
|
private int mSampleRate = 8000;
|
||||||
private String mURL;
|
private String mURL;
|
||||||
@@ -39,6 +39,7 @@ public class IcecastHTTPConfiguration extends BroadcastConfiguration
|
|||||||
public IcecastHTTPConfiguration()
|
public IcecastHTTPConfiguration()
|
||||||
{
|
{
|
||||||
//no-arg JAXB constructor
|
//no-arg JAXB constructor
|
||||||
|
this(BroadcastFormat.MP3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,6 +48,7 @@ public class IcecastHTTPConfiguration extends BroadcastConfiguration
|
|||||||
public IcecastHTTPConfiguration(BroadcastFormat format)
|
public IcecastHTTPConfiguration(BroadcastFormat format)
|
||||||
{
|
{
|
||||||
super(format);
|
super(format);
|
||||||
|
setPassword("change me!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -103,16 +105,25 @@ public class IcecastHTTPConfiguration extends BroadcastConfiguration
|
|||||||
return "Basic " + base64;
|
return "Basic " + base64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User name. Default is 'source'.
|
||||||
|
*/
|
||||||
public String getUserName()
|
public String getUserName()
|
||||||
{
|
{
|
||||||
return mUserName;
|
return mUserName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the user name.
|
||||||
|
*/
|
||||||
public void setUserName(String userName)
|
public void setUserName(String userName)
|
||||||
{
|
{
|
||||||
mUserName = userName;
|
mUserName = userName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this configuration has a user name
|
||||||
|
*/
|
||||||
public boolean hasUserName()
|
public boolean hasUserName()
|
||||||
{
|
{
|
||||||
return mUserName != null;
|
return mUserName != null;
|
||||||
@@ -136,22 +147,34 @@ public class IcecastHTTPConfiguration extends BroadcastConfiguration
|
|||||||
mMountPoint = mountPoint;
|
mMountPoint = mountPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this configuration has a mount point
|
||||||
|
*/
|
||||||
public boolean hasMountPoint()
|
public boolean hasMountPoint()
|
||||||
{
|
{
|
||||||
return mMountPoint != null;
|
return mMountPoint != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stream description
|
||||||
|
*/
|
||||||
public String getDescription()
|
public String getDescription()
|
||||||
{
|
{
|
||||||
return mDescription;
|
return mDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the stream description
|
||||||
|
*/
|
||||||
public void setDescription(String description)
|
public void setDescription(String description)
|
||||||
{
|
{
|
||||||
mDescription = description;
|
mDescription = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this configuration contains a stream description
|
||||||
|
*/
|
||||||
public boolean hasDescription()
|
public boolean hasDescription()
|
||||||
{
|
{
|
||||||
return mDescription != null;
|
return mDescription != null;
|
||||||
@@ -166,14 +189,16 @@ public class IcecastHTTPConfiguration extends BroadcastConfiguration
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stream genre
|
* Sets the stream genre
|
||||||
* @param genre
|
|
||||||
*/
|
*/
|
||||||
public void setGenre(String genre)
|
public void setGenre(String genre)
|
||||||
{
|
{
|
||||||
mGenre = genre;
|
mGenre = genre;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this configuration contains a genre
|
||||||
|
*/
|
||||||
public boolean hasGenre()
|
public boolean hasGenre()
|
||||||
{
|
{
|
||||||
return mGenre != null;
|
return mGenre != null;
|
||||||
@@ -234,21 +259,33 @@ public class IcecastHTTPConfiguration extends BroadcastConfiguration
|
|||||||
mBitRate = bitRate;
|
mBitRate = bitRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this configuration has a bit rate value
|
||||||
|
*/
|
||||||
public boolean hasBitRate()
|
public boolean hasBitRate()
|
||||||
{
|
{
|
||||||
return mBitRate > 0;
|
return mBitRate > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sample rate of the input PCM audio samples. Default is 8 kHz
|
||||||
|
*/
|
||||||
public int getSampleRate()
|
public int getSampleRate()
|
||||||
{
|
{
|
||||||
return mSampleRate;
|
return mSampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the input PCM audio sample rate
|
||||||
|
*/
|
||||||
public void setSampleRate(int sampleRate)
|
public void setSampleRate(int sampleRate)
|
||||||
{
|
{
|
||||||
mSampleRate = sampleRate;
|
mSampleRate = sampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this configuration contains an audio sample rate
|
||||||
|
*/
|
||||||
public boolean hasSampleRate()
|
public boolean hasSampleRate()
|
||||||
{
|
{
|
||||||
return mSampleRate > 0;
|
return mSampleRate > 0;
|
||||||
@@ -264,13 +301,15 @@ public class IcecastHTTPConfiguration extends BroadcastConfiguration
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* URL associated with the broadcastAudio where users can find additional details.
|
* URL associated with the broadcastAudio where users can find additional details.
|
||||||
* @param url
|
|
||||||
*/
|
*/
|
||||||
public void setURL(String url)
|
public void setURL(String url)
|
||||||
{
|
{
|
||||||
mURL = url;
|
mURL = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this configuration contains a stream URL
|
||||||
|
*/
|
||||||
public boolean hasURL()
|
public boolean hasURL()
|
||||||
{
|
{
|
||||||
return mURL != null;
|
return mURL != null;
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ public class IcecastHTTPConfigurationEditor extends BroadcastConfigurationEditor
|
|||||||
private JTextField mServer;
|
private JTextField mServer;
|
||||||
private JTextField mPort;
|
private JTextField mPort;
|
||||||
private JTextField mMountPoint;
|
private JTextField mMountPoint;
|
||||||
|
private JTextField mUsername;
|
||||||
private JTextField mPassword;
|
private JTextField mPassword;
|
||||||
private JButton mSaveButton;
|
private JButton mSaveButton;
|
||||||
private JButton mResetButton;
|
private JButton mResetButton;
|
||||||
@@ -59,7 +60,7 @@ public class IcecastHTTPConfigurationEditor extends BroadcastConfigurationEditor
|
|||||||
setLayout( new MigLayout( "fill,wrap 2", "[align right][grow,fill]", "[][][][][][][][][][grow,fill]" ) );
|
setLayout( new MigLayout( "fill,wrap 2", "[align right][grow,fill]", "[][][][][][][][][][grow,fill]" ) );
|
||||||
setPreferredSize(new Dimension(150,400));
|
setPreferredSize(new Dimension(150,400));
|
||||||
|
|
||||||
JLabel channelLabel = new JLabel("Icecast 2.4+ Stream");
|
JLabel channelLabel = new JLabel("Icecast 2 (v2.4+) Stream");
|
||||||
|
|
||||||
ImageIcon icon = mSettingsManager.getImageIcon(BroadcastServerType.ICECAST_HTTP.getIconName(), 25);
|
ImageIcon icon = mSettingsManager.getImageIcon(BroadcastServerType.ICECAST_HTTP.getIconName(), 25);
|
||||||
channelLabel.setIcon(icon);
|
channelLabel.setIcon(icon);
|
||||||
@@ -90,6 +91,12 @@ public class IcecastHTTPConfigurationEditor extends BroadcastConfigurationEditor
|
|||||||
mMountPoint.setToolTipText("Mount point (e.g. \\12345)");
|
mMountPoint.setToolTipText("Mount point (e.g. \\12345)");
|
||||||
add(mMountPoint);
|
add(mMountPoint);
|
||||||
|
|
||||||
|
add(new JLabel("User Name:"));
|
||||||
|
mUsername = new JTextField();
|
||||||
|
mUsername.getDocument().addDocumentListener(this);
|
||||||
|
mUsername.setToolTipText("User name for the stream. Default: source");
|
||||||
|
add(mUsername);
|
||||||
|
|
||||||
add(new JLabel("Password:"));
|
add(new JLabel("Password:"));
|
||||||
mPassword = new JTextField();
|
mPassword = new JTextField();
|
||||||
mPassword.getDocument().addDocumentListener(this);
|
mPassword.getDocument().addDocumentListener(this);
|
||||||
@@ -158,6 +165,7 @@ public class IcecastHTTPConfigurationEditor extends BroadcastConfigurationEditor
|
|||||||
mServer.setText(config.getHost());
|
mServer.setText(config.getHost());
|
||||||
mPort.setText(config.getPort() != 0 ? String.valueOf(config.getPort()) : null);
|
mPort.setText(config.getPort() != 0 ? String.valueOf(config.getPort()) : null);
|
||||||
mMountPoint.setText(config.getMountPoint());
|
mMountPoint.setText(config.getMountPoint());
|
||||||
|
mUsername.setText(config.getUserName());
|
||||||
mPassword.setText(config.getPassword());
|
mPassword.setText(config.getPassword());
|
||||||
mEnabled.setSelected(config.isEnabled());
|
mEnabled.setSelected(config.isEnabled());
|
||||||
}
|
}
|
||||||
@@ -167,6 +175,7 @@ public class IcecastHTTPConfigurationEditor extends BroadcastConfigurationEditor
|
|||||||
mServer.setText(null);
|
mServer.setText(null);
|
||||||
mPort.setText(null);
|
mPort.setText(null);
|
||||||
mMountPoint.setText(null);
|
mMountPoint.setText(null);
|
||||||
|
mUsername.setText(null);
|
||||||
mPassword.setText(null);
|
mPassword.setText(null);
|
||||||
mEnabled.setSelected(false);
|
mEnabled.setSelected(false);
|
||||||
}
|
}
|
||||||
@@ -185,6 +194,7 @@ public class IcecastHTTPConfigurationEditor extends BroadcastConfigurationEditor
|
|||||||
config.setHost(mServer.getText());
|
config.setHost(mServer.getText());
|
||||||
config.setPort(getPort());
|
config.setPort(getPort());
|
||||||
config.setMountPoint(mMountPoint.getText());
|
config.setMountPoint(mMountPoint.getText());
|
||||||
|
config.setUserName(mUsername.getText());
|
||||||
config.setPassword(mPassword.getText());
|
config.setPassword(mPassword.getText());
|
||||||
config.setEnabled(mEnabled.isSelected());
|
config.setEnabled(mEnabled.isSelected());
|
||||||
|
|
||||||
@@ -228,16 +238,22 @@ public class IcecastHTTPConfigurationEditor extends BroadcastConfigurationEditor
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Mount Point is optional, but required
|
//Mount Point is required
|
||||||
if(!validateTextField(mMountPoint, "Invalid Mount Point", "Please specify a mount point."))
|
if(!validateTextField(mMountPoint, "Invalid Mount Point", "Please specify a mount point."))
|
||||||
{
|
{
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Password is optional, but required
|
//User name is required
|
||||||
|
if(!validateTextField(mUsername, "Invalid User Name", "Please specify a user name."))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Password is required
|
||||||
if(!validateTextField(mPassword, "Invalid Password", "Please specify a password."))
|
if(!validateTextField(mPassword, "Invalid Password", "Please specify a password."))
|
||||||
{
|
{
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public class IcecastTCPConfigurationEditor extends BroadcastConfigurationEditor
|
|||||||
setLayout( new MigLayout( "fill,wrap 2", "[align right][grow,fill]", "[][][][][][][][][][grow,fill]" ) );
|
setLayout( new MigLayout( "fill,wrap 2", "[align right][grow,fill]", "[][][][][][][][][][grow,fill]" ) );
|
||||||
setPreferredSize(new Dimension(150,400));
|
setPreferredSize(new Dimension(150,400));
|
||||||
|
|
||||||
JLabel channelLabel = new JLabel("Icecast 2.3 Stream");
|
JLabel channelLabel = new JLabel("Icecast (v2.3) Stream");
|
||||||
|
|
||||||
ImageIcon icon = mSettingsManager.getImageIcon(BroadcastServerType.ICECAST_TCP.getIconName(), 25);
|
ImageIcon icon = mSettingsManager.getImageIcon(BroadcastServerType.ICECAST_TCP.getIconName(), 25);
|
||||||
channelLabel.setIcon(icon);
|
channelLabel.setIcon(icon);
|
||||||
|
|||||||
Reference in New Issue
Block a user