1 package org.musicontroller.streaming;
2
3 import java.io.FilterOutputStream;
4 import java.io.IOException;
5 import java.io.OutputStream;
6
7 import org.apache.log4j.Logger;
8
9
10
11
12
13 public class ShoutcastOutputStream extends FilterOutputStream {
14 private static final Logger log = Logger.getLogger(ShoutcastOutputStream.class);
15
16 private final static int DEFAULT_METADATA_INTERVAL = 16384;
17 private final static int METADATA_REPEAT_INTERVAL = 1024*1024/DEFAULT_METADATA_INTERVAL;
18 private int metadata_interval;
19 private int intervalcounter;
20 private int count;
21 private byte[] buffer;
22 private String metadata;
23 private boolean metadatachanged;
24 private boolean dooutputmetadata;
25
26
27
28
29 public ShoutcastOutputStream(OutputStream out) {
30 this(out,DEFAULT_METADATA_INTERVAL,true);
31 }
32
33 public ShoutcastOutputStream(OutputStream out, boolean outputmetadata) {
34 this(out,DEFAULT_METADATA_INTERVAL,outputmetadata);
35 }
36
37
38
39
40
41
42
43
44 public ShoutcastOutputStream(OutputStream out, int interval, boolean outputmetadata) {
45 super(out);
46
47 metadata_interval = interval;
48 dooutputmetadata = outputmetadata;
49 buffer = new byte[metadata_interval];
50 count = 0;
51 log.debug("New ShoutcastOutputStream created");
52 }
53
54 private void flushBuffer() throws IOException {
55 if (count==metadata_interval) {
56 out.write(buffer,0,metadata_interval);
57 count = 0;
58 intervalcounter++;
59 if (intervalcounter>METADATA_REPEAT_INTERVAL) {
60 intervalcounter = 0;
61 metadatachanged = true;
62 }
63 if (dooutputmetadata) writeMetaData();
64 } else {
65 log.debug("Incomplete flush, ignoring.");
66 }
67 }
68
69 public synchronized void write(int b) throws IOException {
70 if (count >= buffer.length) {
71 flushBuffer();
72 }
73 buffer[count++] = (byte) b;
74 }
75
76 public synchronized void write(byte[] b, int off, int len) throws IOException {
77 int towrite = len;
78 while (towrite>metadata_interval-count) {
79 System.arraycopy(b, off+len-towrite, buffer, count, metadata_interval-count);
80 towrite -= metadata_interval-count;
81 count+=metadata_interval-count;
82 flushBuffer();
83 }
84 if (towrite>0) {
85 System.arraycopy(b, off+len-towrite, buffer, count, towrite);
86 count+=towrite;
87 }
88 }
89
90 public synchronized void flush() throws IOException {
91 flushBuffer();
92 out.flush();
93 }
94
95
96
97
98
99
100 public void setMetadata(String streamtitle, String streamurl) {
101 metadata = "StreamTitle='" + streamtitle + "';" +
102 "StreamUrl='" + streamurl + "';";
103 metadatachanged = true;
104 }
105
106
107
108
109
110 private void writeMetaData() throws IOException {
111 byte[] size = new byte[1];
112 if (metadatachanged) {
113 byte[] bytes = metadata.getBytes("ISO-8859-1");
114
115
116 int bytesToAdd = (16 - (bytes.length % 16)) % 16;
117 byte[] toAdd = new byte[bytesToAdd];
118
119 size[0] = Integer.valueOf((bytes.length+toAdd.length) / 16).byteValue();
120
121 out.write(size);
122 if (size[0]!=0) {
123 out.write(bytes);
124 out.write(toAdd);
125 }
126 metadatachanged = false;
127 log.debug("Streaming metadata: "+metadata);
128 } else {
129 size[0]=0;
130 out.write(size);
131 }
132 }
133
134 }