Skip to content

Commit ed15478

Browse files
committed
test: CustomAudioSource unit tests
1 parent 82f45a8 commit ed15478

File tree

2 files changed

+150
-0
lines changed

2 files changed

+150
-0
lines changed

webrtc/src/main/java/dev/onvoid/webrtc/media/audio/CustomAudioSource.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,38 @@
1616

1717
package dev.onvoid.webrtc.media.audio;
1818

19+
/**
20+
* Custom implementation of an audio source for WebRTC that allows pushing audio data
21+
* from external sources directly to the WebRTC audio pipeline.
22+
*
23+
* @author Alex Andres
24+
*/
1925
public class CustomAudioSource extends AudioTrackSource {
2026

27+
/**
28+
* Constructs a new CustomAudioSource instance.
29+
*/
2130
public CustomAudioSource() {
2231
super();
2332

2433
initialize();
2534
}
2635

36+
/**
37+
* Pushes audio data to be processed by this audio source.
38+
*
39+
* @param audioData The raw audio data bytes to process.
40+
* @param bits_per_sample The number of bits per sample (e.g., 8, 16, 32).
41+
* @param sampleRate The sample rate of the audio in Hz (e.g., 44100, 48000).
42+
* @param channels The number of audio channels (1 for mono, 2 for stereo).
43+
* @param frameCount The number of frames in the provided audio data.
44+
*/
2745
public native void pushAudio(byte[] audioData, int bits_per_sample,
2846
int sampleRate, int channels, int frameCount);
2947

48+
/**
49+
* Initializes the native resources required by this audio source.
50+
*/
3051
private native void initialize();
3152

3253
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
* Copyright 2025 Alex Andres
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package dev.onvoid.webrtc.media.audio;
18+
19+
import static org.junit.jupiter.api.Assertions.*;
20+
21+
import dev.onvoid.webrtc.TestBase;
22+
import dev.onvoid.webrtc.media.MediaSource;
23+
24+
import org.junit.jupiter.api.AfterEach;
25+
import org.junit.jupiter.api.BeforeEach;
26+
import org.junit.jupiter.api.Test;
27+
28+
import java.util.concurrent.atomic.AtomicBoolean;
29+
import java.util.concurrent.atomic.AtomicInteger;
30+
31+
class CustomAudioSourceTest extends TestBase {
32+
33+
private CustomAudioSource customAudioSource;
34+
35+
36+
@BeforeEach
37+
void init() {
38+
customAudioSource = new CustomAudioSource();
39+
}
40+
41+
@AfterEach
42+
void dispose() {
43+
44+
}
45+
46+
@Test
47+
void stateAfterCreation() {
48+
assertEquals(MediaSource.State.LIVE, customAudioSource.getState());
49+
}
50+
51+
@Test
52+
void addNullSink() {
53+
assertThrows(NullPointerException.class, () -> {
54+
AudioTrack audioTrack = factory.createAudioTrack("audioTrack", customAudioSource);
55+
audioTrack.addSink(null);
56+
audioTrack.dispose();
57+
});
58+
}
59+
60+
@Test
61+
void removeNullSink() {
62+
assertThrows(NullPointerException.class, () -> {
63+
AudioTrack audioTrack = factory.createAudioTrack("audioTrack", customAudioSource);
64+
audioTrack.removeSink(null);
65+
audioTrack.dispose();
66+
});
67+
}
68+
69+
@Test
70+
void addRemoveSink() {
71+
AudioTrack audioTrack = factory.createAudioTrack("audioTrack", customAudioSource);
72+
AudioTrackSink sink = (data, bitsPerSample, sampleRate, channels, frames) -> { };
73+
74+
audioTrack.addSink(sink);
75+
audioTrack.removeSink(sink);
76+
audioTrack.dispose();
77+
}
78+
79+
@Test
80+
void pushAudioData() {
81+
// 16-bit, 48kHz, stereo, 10ms
82+
testAudioFormat(16, 48000, 2, 480);
83+
}
84+
85+
@Test
86+
void pushAudioWithDifferentFormats() {
87+
testAudioFormat(8, 8000, 1, 80); // 8-bit, 8kHz, mono, 10ms
88+
testAudioFormat(16, 16000, 1, 160); // 16-bit, 16kHz, mono, 10ms
89+
testAudioFormat(16, 44100, 2, 441); // 16-bit, 44.1kHz, stereo, 10ms
90+
testAudioFormat(16, 48000, 2, 480); // 16-bit, 48kHz, stereo, 10ms
91+
}
92+
93+
private void testAudioFormat(int bitsPerSample, int sampleRate, int channels, int frameCount) {
94+
AudioTrack audioTrack = factory.createAudioTrack("audioTrack", customAudioSource);
95+
96+
final AtomicBoolean dataReceived = new AtomicBoolean(false);
97+
final AtomicInteger receivedBitsPerSample = new AtomicInteger(0);
98+
final AtomicInteger receivedSampleRate = new AtomicInteger(0);
99+
final AtomicInteger receivedChannels = new AtomicInteger(0);
100+
final AtomicInteger receivedFrames = new AtomicInteger(0);
101+
102+
AudioTrackSink testSink = (data, bits, rate, chans, frames) -> {
103+
dataReceived.set(true);
104+
receivedBitsPerSample.set(bits);
105+
receivedSampleRate.set(rate);
106+
receivedChannels.set(chans);
107+
receivedFrames.set(frames);
108+
};
109+
110+
audioTrack.addSink(testSink);
111+
112+
// Create a buffer with test audio data (silence in this case).
113+
int bytesPerSample = bitsPerSample / 8;
114+
byte[] audioData = new byte[frameCount * channels * bytesPerSample];
115+
116+
customAudioSource.pushAudio(audioData, bitsPerSample, sampleRate, channels, frameCount);
117+
118+
// Verify that our sink received the data with correct parameters.
119+
assertTrue(dataReceived.get(), "Audio data was not received by the sink");
120+
assertEquals(bitsPerSample, receivedBitsPerSample.get(), "Bits per sample doesn't match");
121+
assertEquals(sampleRate, receivedSampleRate.get(), "Sample rate doesn't match");
122+
assertEquals(channels, receivedChannels.get(), "Channel count doesn't match");
123+
assertEquals(frameCount, receivedFrames.get(), "Frame count doesn't match");
124+
125+
// Clean up.
126+
audioTrack.removeSink(testSink);
127+
audioTrack.dispose();
128+
}
129+
}

0 commit comments

Comments
 (0)