2 * Sonitus - MultiSource.java - Copyright © 2013 David Roden
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package net.pterodactylus.sonitus.data.source;
20 import static com.google.common.base.Preconditions.checkNotNull;
22 import java.io.EOFException;
23 import java.io.IOException;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.concurrent.atomic.AtomicReference;
27 import java.util.logging.Logger;
28 import javax.swing.event.EventListenerList;
30 import net.pterodactylus.sonitus.data.AbstractFilter;
31 import net.pterodactylus.sonitus.data.Controller;
32 import net.pterodactylus.sonitus.data.Filter;
33 import net.pterodactylus.sonitus.data.Metadata;
35 import com.google.inject.Inject;
38 * {@link Filter} implementation that simply forwards data from another filter
39 * and supports changing the source without letting downstream filters know.
41 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
43 public class MultiSource extends AbstractFilter {
46 private static final Logger logger = Logger.getLogger(MultiSource.class.getName());
48 /** The source finished listeners. */
49 private final EventListenerList sourceFinishedListeners = new EventListenerList();
51 /** The current source. */
52 private final AtomicReference<Filter> source = new AtomicReference<Filter>();
54 /** Whether the source was changed. */
55 private boolean sourceChanged;
57 /** Creates a new multi source. */
59 public MultiSource() {
64 // LISTENER MANAGEMENT
68 * Adds a source finished listener to the list of registered listeners.
70 * @param sourceFinishedListener
71 * The source finished listener to add
73 public void addSourceFinishedListener(SourceFinishedListener sourceFinishedListener) {
74 sourceFinishedListeners.add(SourceFinishedListener.class, sourceFinishedListener);
78 * Removes a source finished listener from the list of registered listeners.
80 * @param sourceFinishedListener
81 * The source finished listener to remove
83 public void removeSourceFinishedListener(SourceFinishedListener sourceFinishedListener) {
84 sourceFinishedListeners.remove(SourceFinishedListener.class, sourceFinishedListener);
92 * Sets the new source to use.
95 * The new source to use
97 public void setSource(Filter source) {
98 checkNotNull(source, "source must not be null");
100 Filter oldSource = this.source.getAndSet(source);
101 if (!source.equals(oldSource)) {
102 synchronized (this.source) {
103 sourceChanged = true;
104 this.source.notifyAll();
106 metadataUpdated(source.metadata());
107 logger.info(String.format("Next Source set: %s", source));
116 * Notifies all registered listeners that the current source finished playing
117 * and that a new source should be {@link #setSource(Filter) set}.
119 * @see SourceFinishedListener
121 private void fireSourceFinished() {
122 for (SourceFinishedListener sourceFinishedListener : sourceFinishedListeners.getListeners(SourceFinishedListener.class)) {
123 sourceFinishedListener.sourceFinished(this);
132 public List<Controller<?>> controllers() {
133 return Collections.emptyList();
137 public Metadata metadata() {
138 if (super.metadata() == null) {
139 /* no metadata yet, wait for it. */
141 sourceChanged = false;
143 return super.metadata();
147 public byte[] get(int bufferSize) throws EOFException, IOException {
150 return source.get().get(bufferSize);
151 } catch (EOFException eofe1) {
154 synchronized (source) {
155 sourceChanged = false;
165 /** Waits for a new source to be {@link #setSource(Filter) set}. */
166 private void waitForNewSource() {
167 fireSourceFinished();
168 synchronized (source) {
169 while (!sourceChanged) {
171 logger.info("Waiting for next Source...");
173 logger.info("Was notified.");
174 } catch (InterruptedException ioe1) {
175 /* ignore: we’ll end up here again if we were interrupted. */