#30 WIP - icecast 2 broadcaster cleanup

This commit is contained in:
Denny
2016-12-10 10:21:08 -05:00
parent 293dec8a1c
commit 4290d8e403
17 changed files with 129 additions and 125 deletions

Binary file not shown.

View File

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

View File

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

View File

@@ -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;

View File

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

View File

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

View File

@@ -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;

View File

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

View File

@@ -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;

View File

@@ -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;

View File

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