1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
package invalid.lena.scrcpy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class AudioStreamTest {
private static final long FLAG_CONFIG = 1L << 62;
private static final class RecordingFrames implements AudioFrames {
int starts = 0, releases = 0, startFourcc = 0;
final List<byte[]> feeds = new ArrayList<>();
final List<Boolean> cfgs = new ArrayList<>();
@Override public void start(int fourcc) { starts++; startFourcc = fourcc; }
@Override public void feed(byte[] data, int off, int len, boolean isConfig) {
byte[] cp = new byte[len];
System.arraycopy(data, off, cp, 0, len);
feeds.add(cp);
cfgs.add(isConfig);
}
@Override public void release() { releases++; }
}
private static byte[] fourcc(int v) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
new DataOutputStream(bos).writeInt(v);
return bos.toByteArray();
}
private static byte[] frame(long ptsAndFlags, byte[] payload) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(bos);
out.writeLong(ptsAndFlags);
out.writeInt(payload.length);
out.write(payload);
return bos.toByteArray();
}
private static byte[] cat(byte[]... parts) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
for (byte[] p : parts) bos.write(p);
return bos.toByteArray();
}
@Test
public void rawCodecFeedsFrames() throws Exception {
byte[] pcm1 = new byte[]{1, 2, 3, 4};
byte[] pcm2 = new byte[]{5, 6, 7, 8, 9, 10};
byte[] bytes = cat(
fourcc(Wire.CODEC_RAW),
frame(1_000_000L, pcm1),
frame(2_000_000L, pcm2));
RecordingFrames sink = new RecordingFrames();
new AudioStream(new ByteArrayInputStream(bytes), sink).run();
assertEquals(1, sink.starts);
assertEquals(Wire.CODEC_RAW, sink.startFourcc);
assertEquals(2, sink.feeds.size());
assertEquals(pcm1.length, sink.feeds.get(0).length);
assertEquals(pcm2.length, sink.feeds.get(1).length);
for (int i = 0; i < pcm1.length; i++) assertEquals(pcm1[i], sink.feeds.get(0)[i]);
for (int i = 0; i < pcm2.length; i++) assertEquals(pcm2[i], sink.feeds.get(1)[i]);
assertEquals(false, sink.cfgs.get(0));
assertEquals(false, sink.cfgs.get(1));
}
@Test
public void opusConfigFlagIsExposed() throws Exception {
byte[] head = new byte[]{
'O','p','u','s','H','e','a','d', // magic
1, // version
2, // channel count
(byte)0x38, 0x01, // pre-skip = 312 LE
(byte)0x80, (byte)0xBB, 0, 0, // sample rate 48000 LE
0, 0, // output gain
0 // channel mapping family
};
byte[] pkt = new byte[]{0x10, 0x20, 0x30};
byte[] bytes = cat(
fourcc(Wire.CODEC_OPUS),
frame(FLAG_CONFIG, head),
frame(0L, pkt));
RecordingFrames sink = new RecordingFrames();
new AudioStream(new ByteArrayInputStream(bytes), sink).run();
assertEquals(1, sink.starts);
assertEquals(Wire.CODEC_OPUS, sink.startFourcc);
assertEquals(2, sink.feeds.size());
assertTrue("first frame must carry FLAG_CONFIG", sink.cfgs.get(0));
assertTrue("second frame must not carry FLAG_CONFIG", !sink.cfgs.get(1));
assertEquals(head.length, sink.feeds.get(0).length);
assertEquals(pkt.length, sink.feeds.get(1).length);
}
@Test
public void disabledCodecDoesNotStart() throws Exception {
byte[] bytes = fourcc(0);
RecordingFrames sink = new RecordingFrames();
new AudioStream(new ByteArrayInputStream(bytes), sink).run();
assertEquals(0, sink.starts);
assertEquals(0, sink.feeds.size());
}
@Test
public void errorCodecDoesNotStart() throws Exception {
byte[] bytes = fourcc(1);
RecordingFrames sink = new RecordingFrames();
new AudioStream(new ByteArrayInputStream(bytes), sink).run();
assertEquals(0, sink.starts);
assertEquals(0, sink.feeds.size());
}
}
|