1   package org.daisy.pipeline.audio;
2   
3   import java.io.InputStream;
4   import java.util.ArrayList;
5   import java.util.Collection;
6   import java.util.Iterator;
7   import java.util.List;
8   import java.util.concurrent.CopyOnWriteArrayList;
9   import java.util.Map;
10  import java.util.Optional;
11  
12  import javax.sound.sampled.AudioFileFormat;
13  import javax.sound.sampled.AudioInputStream;
14  import javax.sound.sampled.UnsupportedAudioFileException;
15  
16  import org.osgi.service.component.annotations.Component;
17  import org.osgi.service.component.annotations.Reference;
18  import org.osgi.service.component.annotations.ReferenceCardinality;
19  import org.osgi.service.component.annotations.ReferencePolicy;
20  
21  @Component(
22  	name = "audio-services",
23  	service = { AudioServices.class }
24  )
25  public class AudioServices {
26  
27  	public Optional<AudioEncoder> newEncoder(AudioFileFormat.Type fileType, Map<String,String> params) {
28  		for (AudioEncoderService s : encoderServices) {
29  			if (s.supportsFileType(fileType)) {
30  				Optional<AudioEncoder> e = s.newEncoder(params);
31  				if (e.isPresent())
32  					return e;
33  			}
34  		}
35  		return Optional.empty();
36  	}
37  
38  	/**
39  	 * Create a Decoder that can handle any file format supported by the system.
40  	 */
41  	public Optional<AudioDecoder> newDecoder(Map<String,String> params) {
42  		List<AudioDecoder> decoders = new ArrayList<>();
43  		Iterator<AudioDecoderService> decoderServices = this.decoderServices.iterator();
44  		return Optional.of(
45  			new AudioDecoder() {
46  				public AudioInputStream decode(InputStream input) throws UnsupportedAudioFileException, Throwable {
47  					for (AudioDecoder d : decoders) {
48  						try {
49  							return d.decode(input);
50  						} catch (UnsupportedAudioFileException e) {
51  						}
52  					}
53  					while (decoderServices.hasNext()) {
54  						Optional<AudioDecoder> d = decoderServices.next().newDecoder(params);
55  						if (d.isPresent()) {
56  							decoders.add(d.get());
57  							try {
58  								return d.get().decode(input);
59  							} catch (UnsupportedAudioFileException e) {
60  							}
61  						}
62  					}
63  					throw new UnsupportedAudioFileException();
64  				}
65  			}
66  		);
67  	}
68  
69  	public Optional<AudioDecoder> newDecoder(AudioFileFormat.Type fileType, Map<String,String> params) {
70  		for (AudioDecoderService s : decoderServices) {
71  			if (s.supportsFileType(fileType)) {
72  				Optional<AudioDecoder> d = s.newDecoder(params);
73  				if (d.isPresent())
74  					return d;
75  			}
76  		}
77  		return Optional.empty();
78  	}
79  
80  	private final Collection<AudioEncoderService> encoderServices = new CopyOnWriteArrayList<>();
81  	private final Collection<AudioDecoderService> decoderServices = new CopyOnWriteArrayList<>();
82  
83  	@Reference(
84  		name = "audio-encoder-service",
85  		unbind = "-",
86  		service = AudioEncoderService.class,
87  		cardinality = ReferenceCardinality.MULTIPLE,
88  		policy = ReferencePolicy.STATIC
89  	)
90  	public void addEncoderService(AudioEncoderService service) {
91  		encoderServices.add(service);
92  	}
93  
94  	public void removeEncoderService(AudioEncoderService service) {
95  		encoderServices.remove(service);
96  	}
97  
98  	@Reference(
99  		name = "audio-decoder-service",
100 		unbind = "-",
101 		service = AudioDecoderService.class,
102 		cardinality = ReferenceCardinality.MULTIPLE,
103 		policy = ReferencePolicy.STATIC
104 	)
105 	public void addDecoderService(AudioDecoderService service) {
106 		decoderServices.add(service);
107 	}
108 
109 	public void removeDecoderService(AudioDecoderService service) {
110 		decoderServices.remove(service);
111 	}
112 }