Skip to content

Commit e175a77

Browse files
Googlercopybara-github
authored andcommitted
Move AudioGraph effects to configure method
Move old configure behavior to private configureMixer. registerInput() is now required after reset(). PiperOrigin-RevId: 612795418
1 parent c79ac5b commit e175a77

File tree

3 files changed

+80
-77
lines changed

3 files changed

+80
-77
lines changed

libraries/transformer/src/main/java/androidx/media3/transformer/AudioGraph.java

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import static androidx.media3.common.audio.AudioProcessor.EMPTY_BUFFER;
2020
import static androidx.media3.common.util.Assertions.checkArgument;
21+
import static androidx.media3.common.util.Assertions.checkState;
2122

2223
import android.util.SparseArray;
2324
import androidx.media3.common.C;
@@ -34,17 +35,17 @@
3435
/* package */ final class AudioGraph {
3536
private final AudioMixer mixer;
3637
private final SparseArray<AudioGraphInput> inputs;
37-
private final AudioProcessingPipeline audioProcessingPipeline;
3838

39+
private AudioProcessingPipeline audioProcessingPipeline;
3940
private AudioFormat mixerAudioFormat;
4041
private int finishedInputs;
4142
private ByteBuffer mixerOutput;
4243

4344
/** Creates an instance. */
44-
public AudioGraph(AudioMixer.Factory mixerFactory, ImmutableList<AudioProcessor> effects) {
45+
public AudioGraph(AudioMixer.Factory mixerFactory) {
4546
mixer = mixerFactory.create();
4647
inputs = new SparseArray<>();
47-
audioProcessingPipeline = new AudioProcessingPipeline(effects);
48+
audioProcessingPipeline = new AudioProcessingPipeline(ImmutableList.of());
4849
mixerOutput = EMPTY_BUFFER;
4950
mixerAudioFormat = AudioFormat.NOT_SET;
5051
}
@@ -64,28 +65,26 @@ public static boolean isInputAudioFormatValid(AudioFormat format) {
6465
}
6566

6667
/**
67-
* Configures the graph.
68-
*
69-
* <p>Must be called before {@linkplain #getOutput() accessing output}.
68+
* Configures the composition-level audio effects to be applied after mixing.
7069
*
71-
* <p>Should be called at most once, before {@link #registerInput registering input}.
70+
* <p>Must be called before {@linkplain #registerInput(EditedMediaItem, Format) registering
71+
* inputs}.
7272
*
73-
* @param mixerAudioFormat The {@link AudioFormat} requested for output from the mixer.
74-
* @throws UnhandledAudioFormatException If the audio format is not supported by the {@link
75-
* AudioMixer}.
73+
* @param effects The composition-level audio effects.
74+
* @throws IllegalStateException If {@link #registerInput(EditedMediaItem, Format)} was already
75+
* called.
7676
*/
77-
public void configure(AudioFormat mixerAudioFormat) throws UnhandledAudioFormatException {
78-
this.mixerAudioFormat = mixerAudioFormat;
79-
mixer.configure(mixerAudioFormat, /* bufferSizeMs= */ C.LENGTH_UNSET, /* startTimeUs= */ 0);
80-
audioProcessingPipeline.configure(mixerAudioFormat);
81-
audioProcessingPipeline.flush();
77+
public void configure(ImmutableList<AudioProcessor> effects) {
78+
checkState(
79+
mixerAudioFormat.equals(AudioFormat.NOT_SET),
80+
"AudioGraph can't configure effects after input registration.");
81+
audioProcessingPipeline = new AudioProcessingPipeline(effects);
8282
}
8383

8484
/**
8585
* Returns a new {@link AudioGraphInput} instance.
8686
*
87-
* <p>Calls {@link #configure} if not already configured, using the {@linkplain
88-
* AudioGraphInput#getOutputAudioFormat() outputAudioFormat} of the input.
87+
* <p>Must be called before {@linkplain #getOutput() accessing output}.
8988
*/
9089
public AudioGraphInput registerInput(EditedMediaItem editedMediaItem, Format format)
9190
throws ExportException {
@@ -95,8 +94,8 @@ public AudioGraphInput registerInput(EditedMediaItem editedMediaItem, Format for
9594
new AudioGraphInput(mixerAudioFormat, editedMediaItem, format);
9695

9796
if (Objects.equals(mixerAudioFormat, AudioFormat.NOT_SET)) {
98-
// Graph not configured, configure before doing anything else.
99-
configure(audioGraphInput.getOutputAudioFormat());
97+
// Mixer not configured, configure before doing anything else.
98+
configureMixer(audioGraphInput.getOutputAudioFormat());
10099
}
101100

102101
int sourceId = mixer.addSource(audioGraphInput.getOutputAudioFormat(), /* startTimeUs= */ 0);
@@ -109,7 +108,8 @@ public AudioGraphInput registerInput(EditedMediaItem editedMediaItem, Format for
109108

110109
/**
111110
* Returns the {@link AudioFormat} of the {@linkplain #getOutput() output}, or {@link
112-
* AudioFormat#NOT_SET} if not {@linkplain #configure configured}.
111+
* AudioFormat#NOT_SET} if no inputs were {@linkplain #registerInput(EditedMediaItem, Format)
112+
* registered} previously.
113113
*/
114114
public AudioFormat getOutputAudioFormat() {
115115
return audioProcessingPipeline.getOutputAudioFormat();
@@ -136,7 +136,11 @@ public ByteBuffer getOutput() throws ExportException {
136136
return mixerOutput;
137137
}
138138

139-
/** Resets the graph to an unconfigured state, releasing any underlying resources. */
139+
/**
140+
* Resets the graph, un-registering inputs and releasing any underlying resources.
141+
*
142+
* <p>Call {@link #registerInput(EditedMediaItem, Format)} to prepare the audio graph again.
143+
*/
140144
public void reset() {
141145
for (int i = 0; i < inputs.size(); i++) {
142146
inputs.valueAt(i).release();
@@ -158,6 +162,22 @@ public boolean isEnded() {
158162
return isMixerEnded();
159163
}
160164

165+
/**
166+
* Configures the mixer.
167+
*
168+
* <p>Must be called before {@linkplain #getOutput() accessing output}.
169+
*
170+
* @param mixerAudioFormat The {@link AudioFormat} requested for output from the mixer.
171+
* @throws UnhandledAudioFormatException If the audio format is not supported by the {@link
172+
* AudioMixer}.
173+
*/
174+
private void configureMixer(AudioFormat mixerAudioFormat) throws UnhandledAudioFormatException {
175+
this.mixerAudioFormat = mixerAudioFormat;
176+
mixer.configure(mixerAudioFormat, /* bufferSizeMs= */ C.LENGTH_UNSET, /* startTimeUs= */ 0);
177+
audioProcessingPipeline.configure(mixerAudioFormat);
178+
audioProcessingPipeline.flush();
179+
}
180+
161181
private boolean isMixerEnded() {
162182
return !mixerOutput.hasRemaining() && finishedInputs >= inputs.size() && mixer.isEnded();
163183
}

libraries/transformer/src/main/java/androidx/media3/transformer/AudioSampleExporter.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ public AudioSampleExporter(
5959
FallbackListener fallbackListener)
6060
throws ExportException {
6161
super(firstAssetLoaderTrackFormat, muxerWrapper);
62-
audioGraph = new AudioGraph(mixerFactory, compositionAudioProcessors);
62+
audioGraph = new AudioGraph(mixerFactory);
63+
audioGraph.configure(compositionAudioProcessors);
6364
this.firstInputFormat = firstInputFormat;
6465
firstInput = audioGraph.registerInput(firstEditedMediaItem, firstInputFormat);
6566
encoderInputAudioFormat = audioGraph.getOutputAudioFormat();

libraries/transformer/src/test/java/androidx/media3/transformer/AudioGraphTest.java

Lines changed: 37 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import static androidx.media3.common.util.Util.getPcmFormat;
1919
import static com.google.common.truth.Truth.assertThat;
20+
import static org.junit.Assert.assertThrows;
2021

2122
import androidx.media3.common.C;
2223
import androidx.media3.common.MediaItem;
@@ -46,8 +47,7 @@ public class AudioGraphTest {
4647

4748
@Test
4849
public void silentItem_outputsCorrectAmountOfBytes() throws Exception {
49-
AudioGraph audioGraph =
50-
new AudioGraph(new DefaultAudioMixer.Factory(), /* effects= */ ImmutableList.of());
50+
AudioGraph audioGraph = new AudioGraph(new DefaultAudioMixer.Factory());
5151

5252
GraphInput input = audioGraph.registerInput(FAKE_ITEM, getPcmFormat(SURROUND_50000));
5353
input.onMediaItemChanged(
@@ -63,9 +63,8 @@ public void silentItem_outputsCorrectAmountOfBytes() throws Exception {
6363
public void silentItem_withSampleRateChange_outputsCorrectAmountOfBytes() throws Exception {
6464
SonicAudioProcessor changeTo100000Hz = new SonicAudioProcessor();
6565
changeTo100000Hz.setOutputSampleRateHz(100_000);
66-
AudioGraph audioGraph =
67-
new AudioGraph(
68-
new DefaultAudioMixer.Factory(), /* effects= */ ImmutableList.of(changeTo100000Hz));
66+
AudioGraph audioGraph = new AudioGraph(new DefaultAudioMixer.Factory());
67+
audioGraph.configure(ImmutableList.of(changeTo100000Hz));
6968

7069
GraphInput input = audioGraph.registerInput(FAKE_ITEM, getPcmFormat(SURROUND_50000));
7170
input.onMediaItemChanged(
@@ -79,48 +78,23 @@ public void silentItem_withSampleRateChange_outputsCorrectAmountOfBytes() throws
7978

8079
@Test
8180
public void getOutputAudioFormat_afterInitialization_isNotSet() {
82-
AudioGraph audioGraph =
83-
new AudioGraph(new DefaultAudioMixer.Factory(), /* effects= */ ImmutableList.of());
81+
AudioGraph audioGraph = new AudioGraph(new DefaultAudioMixer.Factory());
8482

8583
assertThat(audioGraph.getOutputAudioFormat()).isEqualTo(AudioFormat.NOT_SET);
8684
}
8785

8886
@Test
8987
public void getOutputAudioFormat_afterRegisterInput_matchesInputFormat() throws Exception {
90-
AudioGraph audioGraph =
91-
new AudioGraph(new DefaultAudioMixer.Factory(), /* effects= */ ImmutableList.of());
88+
AudioGraph audioGraph = new AudioGraph(new DefaultAudioMixer.Factory());
9289

9390
audioGraph.registerInput(FAKE_ITEM, getPcmFormat(MONO_48000));
9491

9592
assertThat(audioGraph.getOutputAudioFormat()).isEqualTo(MONO_48000);
9693
}
9794

98-
@Test
99-
public void getOutputAudioFormat_afterConfigure_matchesConfiguredFormat() throws Exception {
100-
AudioGraph audioGraph =
101-
new AudioGraph(new DefaultAudioMixer.Factory(), /* effects= */ ImmutableList.of());
102-
103-
audioGraph.configure(/* mixerAudioFormat= */ SURROUND_50000);
104-
105-
assertThat(audioGraph.getOutputAudioFormat()).isEqualTo(SURROUND_50000);
106-
}
107-
108-
@Test
109-
public void registerInput_afterConfigure_doesNotChangeOutputFormat() throws Exception {
110-
AudioGraph audioGraph =
111-
new AudioGraph(new DefaultAudioMixer.Factory(), /* effects= */ ImmutableList.of());
112-
113-
audioGraph.configure(/* mixerAudioFormat= */ STEREO_44100);
114-
audioGraph.registerInput(FAKE_ITEM, getPcmFormat(STEREO_48000));
115-
audioGraph.registerInput(FAKE_ITEM, getPcmFormat(MONO_44100));
116-
117-
assertThat(audioGraph.getOutputAudioFormat()).isEqualTo(STEREO_44100);
118-
}
119-
12095
@Test
12196
public void registerInput_afterRegisterInput_doesNotChangeOutputFormat() throws Exception {
122-
AudioGraph audioGraph =
123-
new AudioGraph(new DefaultAudioMixer.Factory(), /* effects= */ ImmutableList.of());
97+
AudioGraph audioGraph = new AudioGraph(new DefaultAudioMixer.Factory());
12498

12599
audioGraph.registerInput(FAKE_ITEM, getPcmFormat(STEREO_48000));
126100
audioGraph.registerInput(FAKE_ITEM, getPcmFormat(MONO_44100));
@@ -130,8 +104,7 @@ public void registerInput_afterRegisterInput_doesNotChangeOutputFormat() throws
130104

131105
@Test
132106
public void registerInput_afterReset_changesOutputFormat() throws Exception {
133-
AudioGraph audioGraph =
134-
new AudioGraph(new DefaultAudioMixer.Factory(), /* effects= */ ImmutableList.of());
107+
AudioGraph audioGraph = new AudioGraph(new DefaultAudioMixer.Factory());
135108

136109
audioGraph.registerInput(FAKE_ITEM, getPcmFormat(STEREO_48000));
137110
audioGraph.reset();
@@ -140,26 +113,12 @@ public void registerInput_afterReset_changesOutputFormat() throws Exception {
140113
assertThat(audioGraph.getOutputAudioFormat()).isEqualTo(MONO_44100);
141114
}
142115

143-
@Test
144-
public void configure_withAudioProcessor_affectsOutputFormat() throws Exception {
145-
SonicAudioProcessor sonicAudioProcessor = new SonicAudioProcessor();
146-
sonicAudioProcessor.setOutputSampleRateHz(48_000);
147-
AudioGraph audioGraph =
148-
new AudioGraph(
149-
new DefaultAudioMixer.Factory(), /* effects= */ ImmutableList.of(sonicAudioProcessor));
150-
151-
audioGraph.configure(/* mixerAudioFormat= */ SURROUND_50000);
152-
153-
assertThat(audioGraph.getOutputAudioFormat().sampleRate).isEqualTo(48_000);
154-
}
155-
156116
@Test
157117
public void registerInput_withAudioProcessor_affectsOutputFormat() throws Exception {
158118
SonicAudioProcessor sonicAudioProcessor = new SonicAudioProcessor();
159119
sonicAudioProcessor.setOutputSampleRateHz(48_000);
160-
AudioGraph audioGraph =
161-
new AudioGraph(
162-
new DefaultAudioMixer.Factory(), /* effects= */ ImmutableList.of(sonicAudioProcessor));
120+
AudioGraph audioGraph = new AudioGraph(new DefaultAudioMixer.Factory());
121+
audioGraph.configure(ImmutableList.of(sonicAudioProcessor));
163122

164123
audioGraph.registerInput(FAKE_ITEM, getPcmFormat(SURROUND_50000));
165124

@@ -172,16 +131,39 @@ public void registerInput_withMultipleAudioProcessors_affectsOutputFormat() thro
172131
changeTo96000Hz.setOutputSampleRateHz(96_000);
173132
SonicAudioProcessor changeTo48000Hz = new SonicAudioProcessor();
174133
changeTo48000Hz.setOutputSampleRateHz(48_000);
175-
AudioGraph audioGraph =
176-
new AudioGraph(
177-
new DefaultAudioMixer.Factory(),
178-
/* effects= */ ImmutableList.of(changeTo96000Hz, changeTo48000Hz));
134+
AudioGraph audioGraph = new AudioGraph(new DefaultAudioMixer.Factory());
135+
audioGraph.configure(ImmutableList.of(changeTo96000Hz, changeTo48000Hz));
179136

180137
audioGraph.registerInput(FAKE_ITEM, getPcmFormat(SURROUND_50000));
181138

182139
assertThat(audioGraph.getOutputAudioFormat().sampleRate).isEqualTo(48_000);
183140
}
184141

142+
@Test
143+
public void configure_changesOutputFormat() throws Exception {
144+
AudioGraph audioGraph = new AudioGraph(new DefaultAudioMixer.Factory());
145+
SonicAudioProcessor sonicAudioProcessor = new SonicAudioProcessor();
146+
sonicAudioProcessor.setOutputSampleRateHz(48_000);
147+
audioGraph.configure(ImmutableList.of(sonicAudioProcessor));
148+
149+
audioGraph.registerInput(FAKE_ITEM, getPcmFormat(STEREO_44100));
150+
151+
assertThat(audioGraph.getOutputAudioFormat().sampleRate).isEqualTo(48_000);
152+
}
153+
154+
@Test
155+
public void configure_afterRegisterInput_throws() throws Exception {
156+
AudioGraph audioGraph = new AudioGraph(new DefaultAudioMixer.Factory());
157+
SonicAudioProcessor sonicAudioProcessor = new SonicAudioProcessor();
158+
sonicAudioProcessor.setOutputSampleRateHz(48_000);
159+
160+
audioGraph.registerInput(FAKE_ITEM, getPcmFormat(STEREO_44100));
161+
162+
assertThrows(
163+
IllegalStateException.class,
164+
() -> audioGraph.configure(ImmutableList.of(sonicAudioProcessor)));
165+
}
166+
185167
/** Drains the graph and returns the number of bytes output. */
186168
private static int drainAudioGraph(AudioGraph audioGraph) throws ExportException {
187169
int bytesOutput = 0;

0 commit comments

Comments
 (0)