diff --git a/demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java b/demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java index b8d06a146c..dd5160acf0 100644 --- a/demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java +++ b/demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java @@ -311,13 +311,15 @@ public final class TransformerActivity extends AppCompatActivity { new Transformer.Listener() { @Override public void onTransformationCompleted( - MediaItem mediaItem, TransformationResult transformationResult) { + MediaItem mediaItem, TransformationResult result) { TransformerActivity.this.onTransformationCompleted(filePath, mediaItem); } @Override public void onTransformationError( - MediaItem mediaItem, TransformationException exception) { + MediaItem mediaItem, + TransformationResult result, + TransformationException exception) { TransformerActivity.this.onTransformationError(exception); } }) diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformationTestResult.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformationTestResult.java index af8ab7f1c3..b636219487 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformationTestResult.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformationTestResult.java @@ -17,6 +17,7 @@ package androidx.media3.transformer; import androidx.annotation.Nullable; import androidx.media3.common.C; +import androidx.media3.common.util.Assertions; import com.google.errorprone.annotations.CanIgnoreReturnValue; import org.json.JSONException; import org.json.JSONObject; @@ -28,20 +29,33 @@ public class TransformationTestResult { /** A builder for {@link TransformationTestResult}. */ public static class Builder { - private final TransformationResult transformationResult; - + @Nullable private TransformationResult transformationResult; @Nullable private String filePath; - @Nullable private Exception analysisException; private long elapsedTimeMs; private double ssim; + @Nullable private Exception testException; + @Nullable private Exception analysisException; /** Creates a new {@link Builder}. */ - public Builder(TransformationResult transformationResult) { - this.transformationResult = transformationResult; + public Builder() { this.elapsedTimeMs = C.TIME_UNSET; this.ssim = SSIM_UNSET; } + /** + * Sets the {@link TransformationResult} of the transformation. + * + *

This field must be set. + * + * @param transformationResult The {@link TransformationResult}. + * @return This {@link Builder} + */ + @CanIgnoreReturnValue + public Builder setTransformationResult(TransformationResult transformationResult) { + this.transformationResult = transformationResult; + return this; + } + /** * Sets the file path of the output file. * @@ -85,6 +99,20 @@ public class TransformationTestResult { return this; } + /** + * Sets an {@link Exception} that occurred during the test. + * + *

{@code null} represents an unset or unknown value. + * + * @param testException The {@link Exception} thrown during the test. + * @return This {@link Builder}. + */ + @CanIgnoreReturnValue + public Builder setTestException(@Nullable Exception testException) { + this.testException = testException; + return this; + } + /** * Sets an {@link Exception} that occurred during post-transformation analysis. * @@ -102,7 +130,12 @@ public class TransformationTestResult { /** Builds the {@link TransformationTestResult} instance. */ public TransformationTestResult build() { return new TransformationTestResult( - transformationResult, filePath, elapsedTimeMs, ssim, analysisException); + Assertions.checkNotNull(transformationResult), + filePath, + elapsedTimeMs, + ssim, + testException, + analysisException); } } @@ -120,6 +153,12 @@ public class TransformationTestResult { public final long elapsedTimeMs; /** The SSIM score of the transformation, {@link #SSIM_UNSET} if unavailable. */ public final double ssim; + + /** + * The {@link Exception} that was thrown during the test, or {@code null} if nothing was thrown. + */ + @Nullable public final Exception testException; + /** * The {@link Exception} that was thrown during post-transformation analysis, or {@code null} if * nothing was thrown. @@ -165,6 +204,9 @@ public class TransformationTestResult { if (ssim != TransformationTestResult.SSIM_UNSET) { jsonObject.put("ssim", ssim); } + if (testException != null) { + jsonObject.put("testException", AndroidTestUtil.exceptionAsJsonObject(testException)); + } if (analysisException != null) { jsonObject.put("analysisException", AndroidTestUtil.exceptionAsJsonObject(analysisException)); } @@ -176,11 +218,13 @@ public class TransformationTestResult { @Nullable String filePath, long elapsedTimeMs, double ssim, + @Nullable Exception testException, @Nullable Exception analysisException) { this.transformationResult = transformationResult; this.filePath = filePath; this.elapsedTimeMs = elapsedTimeMs; this.ssim = ssim; + this.testException = testException; this.analysisException = analysisException; this.throughputFps = elapsedTimeMs != C.TIME_UNSET && transformationResult.videoFrameCount > 0 diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerAndroidTestRunner.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerAndroidTestRunner.java index b14179f4cf..6b2ae7a035 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerAndroidTestRunner.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerAndroidTestRunner.java @@ -39,7 +39,6 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import org.checkerframework.checker.nullness.compatqual.NullableType; -import org.json.JSONException; import org.json.JSONObject; /** An android instrumentation test runner for {@link Transformer}. */ @@ -153,8 +152,6 @@ public class TransformerAndroidTestRunner { } private final Context context; - private final CapturingDecoderFactory decoderFactory; - private final CapturingEncoderFactory encoderFactory; private final Transformer transformer; private final int timeoutSeconds; private final boolean requestCalculateSsim; @@ -169,14 +166,7 @@ public class TransformerAndroidTestRunner { boolean suppressAnalysisExceptions, @Nullable Map inputValues) { this.context = context; - this.decoderFactory = new CapturingDecoderFactory(transformer.decoderFactory); - this.encoderFactory = new CapturingEncoderFactory(transformer.encoderFactory); - this.transformer = - transformer - .buildUpon() - .setDecoderFactory(decoderFactory) - .setEncoderFactory(encoderFactory) - .build(); + this.transformer = transformer; this.timeoutSeconds = timeoutSeconds; this.requestCalculateSsim = requestCalculateSsim; this.suppressAnalysisExceptions = suppressAnalysisExceptions; @@ -184,7 +174,7 @@ public class TransformerAndroidTestRunner { } /** - * Transforms the {@code uriString}, saving a summary of the transformation to the application + * Transforms the {@link MediaItem}, saving a summary of the transformation to the application * cache. * * @param testId A unique identifier for the transformer test run. @@ -200,35 +190,35 @@ public class TransformerAndroidTestRunner { try { TransformationTestResult transformationTestResult = runInternal(testId, mediaItem); resultJson.put("transformationResult", transformationTestResult.asJsonObject()); + if (transformationTestResult.testException != null) { + throw transformationTestResult.testException; + } if (!suppressAnalysisExceptions && transformationTestResult.analysisException != null) { throw transformationTestResult.analysisException; } return transformationTestResult; - } catch (Exception e) { - resultJson.put("exception", AndroidTestUtil.exceptionAsJsonObject(e)); + } catch (UnsupportedOperationException | InterruptedException | IOException e) { + resultJson.put( + "transformationResult", + new JSONObject().put("testException", AndroidTestUtil.exceptionAsJsonObject(e))); throw e; } finally { - resultJson.put("codecDetails", getCodecNamesAsJsonObject()); AndroidTestUtil.writeTestSummaryToFile(context, testId, resultJson); } } /** - * Transforms the {@code uriString}. + * Transforms the {@link MediaItem}. * * @param testId An identifier for the test. * @param mediaItem The {@link MediaItem} to transform. * @return The {@link TransformationTestResult}. - * @throws IOException If an error occurs opening the output file for writing - * @throws TimeoutException If the transformation takes longer than the {@link #timeoutSeconds}. * @throws InterruptedException If the thread is interrupted whilst waiting for transformer to * complete. - * @throws TransformationException If an exception occurs as a result of the transformation. - * @throws IllegalArgumentException If the path is invalid. - * @throws IllegalStateException If an unexpected exception occurs when starting a transformation. + * @throws IOException If an error occurs opening the output file for writing. */ private TransformationTestResult runInternal(String testId, MediaItem mediaItem) - throws InterruptedException, IOException, TimeoutException, TransformationException { + throws InterruptedException, IOException { if (!mediaItem.clippingConfiguration.equals(MediaItem.ClippingConfiguration.UNSET) && requestCalculateSsim) { throw new UnsupportedOperationException( @@ -266,8 +256,11 @@ public class TransformerAndroidTestRunner { @Override public void onTransformationError( - MediaItem inputMediaItem, TransformationException exception) { + MediaItem inputMediaItem, + TransformationResult result, + TransformationException exception) { transformationExceptionReference.set(exception); + transformationResultReference.set(result); countDownLatch.countDown(); } @@ -302,45 +295,54 @@ public class TransformerAndroidTestRunner { } }); - if (!countDownLatch.await(timeoutSeconds, SECONDS)) { - throw new TimeoutException("Transformer timed out after " + timeoutSeconds + " seconds."); - } - long elapsedTimeMs = SystemClock.DEFAULT.elapsedRealtime() - startTimeMs; + // Block here until timeout reached or latch is counted down. + boolean timeoutReached = !countDownLatch.await(timeoutSeconds, SECONDS); + + TransformationTestResult.Builder testResultBuilder = + new TransformationTestResult.Builder() + .setElapsedTimeMs(SystemClock.DEFAULT.elapsedRealtime() - startTimeMs); @Nullable Exception unexpectedException = unexpectedExceptionReference.get(); - if (unexpectedException != null) { - throw new IllegalStateException( - "Unexpected exception starting the transformer.", unexpectedException); - } - @Nullable TransformationException transformationException = transformationExceptionReference.get(); - if (transformationException != null) { - throw transformationException; + + @Nullable Exception testException = null; + if (timeoutReached) { + testException = + new TimeoutException("Transformer timed out after " + timeoutSeconds + " seconds."); + } else if (unexpectedException != null) { + testException = + new IllegalStateException( + "Unexpected exception starting the transformer.", unexpectedException); + } else if (transformationException != null) { + testException = transformationException; } - // If both exceptions are null, the Transformation must have succeeded, and a - // transformationResult will be available. - TransformationResult transformationResult = - checkNotNull(transformationResultReference.get()) - .buildUpon() - .setFileSizeBytes(outputVideoFile.length()) - .build(); + if (testException != null) { + return testResultBuilder + .setTransformationResult(checkNotNull(transformationResultReference.get())) + .setTestException(testException) + .build(); + } - TransformationTestResult.Builder resultBuilder = - new TransformationTestResult.Builder(transformationResult) - .setFilePath(outputVideoFile.getPath()) - .setElapsedTimeMs(elapsedTimeMs); + // No exceptions raised, transformation has succeeded. + testResultBuilder + .setTransformationResult( + checkNotNull(transformationResultReference.get()) + .buildUpon() + .setFileSizeBytes(outputVideoFile.length()) + .build()) + .setFilePath(outputVideoFile.getPath()); if (!requestCalculateSsim) { - return resultBuilder.build(); + return testResultBuilder.build(); } if (fallbackResolutionApplied.get()) { Log.i( TAG, testId + ": Skipping SSIM calculation because an encoder resolution fallback was applied."); - return resultBuilder.build(); + return testResultBuilder.build(); } try { double ssim = @@ -348,7 +350,7 @@ public class TransformerAndroidTestRunner { context, /* referenceVideoPath= */ checkNotNull(mediaItem.localConfiguration).uri.toString(), /* distortedVideoPath= */ outputVideoFile.getPath()); - resultBuilder.setSsim(ssim); + testResultBuilder.setSsim(ssim); } catch (InterruptedException interruptedException) { // InterruptedException is a special unexpected case because it is not related to Ssim // calculation, so it should be thrown, rather than processed as part of the @@ -366,11 +368,11 @@ public class TransformerAndroidTestRunner { ? (Exception) analysisFailure : new IllegalStateException(analysisFailure); - resultBuilder.setAnalysisException(analysisException); + testResultBuilder.setAnalysisException(analysisException); Log.e(TAG, testId + ": SSIM calculation failed.", analysisException); } } - return resultBuilder.build(); + return testResultBuilder.build(); } /** Returns whether the context is connected to the network. */ @@ -400,21 +402,4 @@ public class TransformerAndroidTestRunner { } return false; } - - private JSONObject getCodecNamesAsJsonObject() throws JSONException { - JSONObject detailsJson = new JSONObject(); - if (decoderFactory.getAudioDecoderName() != null) { - detailsJson.put("audioDecoderName", decoderFactory.getAudioDecoderName()); - } - if (decoderFactory.getVideoDecoderName() != null) { - detailsJson.put("videoDecoderName", decoderFactory.getVideoDecoderName()); - } - if (encoderFactory.getAudioEncoderName() != null) { - detailsJson.put("audioEncoderName", encoderFactory.getAudioEncoderName()); - } - if (encoderFactory.getVideoEncoderName() != null) { - detailsJson.put("videoEncoderName", encoderFactory.getVideoEncoderName()); - } - return detailsJson; - } } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformationResult.java b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformationResult.java index 89fd480de4..f34d6a31b6 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformationResult.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformationResult.java @@ -38,6 +38,7 @@ public final class TransformationResult { @Nullable private String audioEncoderName; @Nullable private String videoDecoderName; @Nullable private String videoEncoderName; + @Nullable private TransformationException transformationException; public Builder() { durationMs = C.TIME_UNSET; @@ -53,7 +54,7 @@ public final class TransformationResult { */ @CanIgnoreReturnValue public Builder setDurationMs(long durationMs) { - checkArgument(durationMs > 0 || durationMs == C.TIME_UNSET); + checkArgument(durationMs >= 0 || durationMs == C.TIME_UNSET); this.durationMs = durationMs; return this; } @@ -134,6 +135,14 @@ public final class TransformationResult { return this; } + /** Sets the {@link TransformationException} that caused the transformation to fail. */ + @CanIgnoreReturnValue + public Builder setTransformationException( + @Nullable TransformationException transformationException) { + this.transformationException = transformationException; + return this; + } + public TransformationResult build() { return new TransformationResult( durationMs, @@ -144,7 +153,8 @@ public final class TransformationResult { audioDecoderName, audioEncoderName, videoDecoderName, - videoEncoderName); + videoEncoderName, + transformationException); } } @@ -162,7 +172,6 @@ public final class TransformationResult { public final int averageVideoBitrate; /** The number of video frames. */ public final int videoFrameCount; - /** The name of the audio decoder used, or {@code null} if none were used. */ @Nullable public final String audioDecoderName; /** The name of the audio encoder used, or {@code null} if none were used. */ @@ -171,6 +180,11 @@ public final class TransformationResult { @Nullable public final String videoDecoderName; /** The name of the video encoder used, or {@code null} if none were used. */ @Nullable public final String videoEncoderName; + /** + * The {@link TransformationException} that caused the transformation to fail, or {@code null} if + * the transformation was a success. + */ + @Nullable public final TransformationException transformationException; private TransformationResult( long durationMs, @@ -181,7 +195,8 @@ public final class TransformationResult { @Nullable String audioDecoderName, @Nullable String audioEncoderName, @Nullable String videoDecoderName, - @Nullable String videoEncoderName) { + @Nullable String videoEncoderName, + @Nullable TransformationException transformationException) { this.durationMs = durationMs; this.fileSizeBytes = fileSizeBytes; this.averageAudioBitrate = averageAudioBitrate; @@ -191,6 +206,7 @@ public final class TransformationResult { this.audioEncoderName = audioEncoderName; this.videoDecoderName = videoDecoderName; this.videoEncoderName = videoEncoderName; + this.transformationException = transformationException; } public Builder buildUpon() { @@ -203,7 +219,8 @@ public final class TransformationResult { .setAudioDecoderName(audioDecoderName) .setAudioEncoderName(audioEncoderName) .setVideoDecoderName(videoDecoderName) - .setVideoEncoderName(videoEncoderName); + .setVideoEncoderName(videoEncoderName) + .setTransformationException(transformationException); } @Override @@ -223,7 +240,8 @@ public final class TransformationResult { && Objects.equals(audioDecoderName, result.audioDecoderName) && Objects.equals(audioEncoderName, result.audioEncoderName) && Objects.equals(videoDecoderName, result.videoDecoderName) - && Objects.equals(videoEncoderName, result.videoEncoderName); + && Objects.equals(videoEncoderName, result.videoEncoderName) + && Objects.equals(transformationException, result.transformationException); } @Override @@ -237,6 +255,7 @@ public final class TransformationResult { result = 31 * result + Objects.hashCode(audioEncoderName); result = 31 * result + Objects.hashCode(videoDecoderName); result = 31 * result + Objects.hashCode(videoEncoderName); + result = 31 * result + Objects.hashCode(transformationException); return result; } } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java index 06d0f84b69..680910eb21 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java @@ -535,21 +535,33 @@ public final class Transformer { } /** - * @deprecated Use {@link #onTransformationError(MediaItem, TransformationException)}. + * @deprecated Use {@link #onTransformationError(MediaItem, TransformationResult, + * TransformationException)}. */ @Deprecated default void onTransformationError(MediaItem inputMediaItem, Exception exception) { onTransformationError(inputMediaItem, (TransformationException) exception); } + /** + * @deprecated Use {@link #onTransformationError(MediaItem, TransformationResult, + * TransformationException)}. + */ + @Deprecated + default void onTransformationError( + MediaItem inputMediaItem, TransformationException exception) { + onTransformationError(inputMediaItem, new TransformationResult.Builder().build(), exception); + } + /** * Called if an exception occurs during the transformation. * * @param inputMediaItem The {@link MediaItem} for which the exception occurs. + * @param result The {@link TransformationResult} of the transformation. * @param exception The {@link TransformationException} describing the exception. */ default void onTransformationError( - MediaItem inputMediaItem, TransformationException exception) {} + MediaItem inputMediaItem, TransformationResult result, TransformationException exception) {} /** * Called when fallback to an alternative {@link TransformationRequest} is necessary to comply @@ -880,13 +892,14 @@ public final class Transformer { } @Override - public void onTransformationError(TransformationException exception) { + public void onTransformationError( + TransformationResult result, TransformationException exception) { handler.post( () -> { transformerInternal = null; listeners.queueEvent( /* eventFlag= */ C.INDEX_UNSET, - listener -> listener.onTransformationError(mediaItem, exception)); + listener -> listener.onTransformationError(mediaItem, result, exception)); listeners.flushEvents(); }); } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java index a4ece1a6ce..7b40f8c7c2 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java @@ -16,7 +16,6 @@ package androidx.media3.transformer; -import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.transformer.TransformationException.ERROR_CODE_MUXING_FAILED; import static androidx.media3.transformer.Transformer.PROGRESS_STATE_NO_TRANSFORMATION; import static java.lang.annotation.ElementType.TYPE_USE; @@ -57,9 +56,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; public interface Listener { - void onTransformationCompleted(TransformationResult transformationResult); + void onTransformationCompleted(TransformationResult result); - void onTransformationError(TransformationException exception); + void onTransformationError(TransformationResult result, TransformationException exception); } /** @@ -300,7 +299,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; private void endInternal( @EndReason int endReason, @Nullable TransformationException transformationException) { - @Nullable TransformationResult transformationResult = null; + TransformationResult.Builder transformationResultBuilder = + new TransformationResult.Builder() + .setAudioDecoderName(decoderFactory.getAudioDecoderName()) + .setVideoDecoderName(decoderFactory.getVideoDecoderName()) + .setAudioEncoderName(encoderFactory.getAudioEncoderName()) + .setVideoEncoderName(encoderFactory.getVideoEncoderName()); + boolean forCancellation = endReason == END_REASON_CANCELLED; @Nullable TransformationException releaseTransformationException = null; if (!released) { @@ -315,26 +320,17 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; assetLoader.release(); } finally { try { - for (int i = 0; i < samplePipelines.size(); i++) { - samplePipelines.get(i).release(); + if (endReason == END_REASON_COMPLETED) { + transformationResultBuilder + .setDurationMs(muxerWrapper.getDurationMs()) + .setFileSizeBytes(muxerWrapper.getCurrentOutputSizeBytes()) + .setAverageAudioBitrate(muxerWrapper.getTrackAverageBitrate(C.TRACK_TYPE_AUDIO)) + .setAverageVideoBitrate(muxerWrapper.getTrackAverageBitrate(C.TRACK_TYPE_VIDEO)) + .setVideoFrameCount(muxerWrapper.getTrackSampleCount(C.TRACK_TYPE_VIDEO)); } - // TODO(b/250564186): Create TransformationResult on END_REASON_ERROR as well. - if (endReason == END_REASON_COMPLETED) { - transformationResult = - new TransformationResult.Builder() - .setDurationMs(checkNotNull(muxerWrapper).getDurationMs()) - .setAverageAudioBitrate( - muxerWrapper.getTrackAverageBitrate(C.TRACK_TYPE_AUDIO)) - .setAverageVideoBitrate( - muxerWrapper.getTrackAverageBitrate(C.TRACK_TYPE_VIDEO)) - .setVideoFrameCount(muxerWrapper.getTrackSampleCount(C.TRACK_TYPE_VIDEO)) - .setFileSizeBytes(muxerWrapper.getCurrentOutputSizeBytes()) - .setAudioDecoderName(decoderFactory.getAudioDecoderName()) - .setAudioEncoderName(encoderFactory.getAudioEncoderName()) - .setVideoDecoderName(decoderFactory.getVideoDecoderName()) - .setVideoEncoderName(encoderFactory.getVideoEncoderName()) - .build(); + for (int i = 0; i < samplePipelines.size(); i++) { + samplePipelines.get(i).release(); } } finally { muxerWrapper.release(forCancellation); @@ -369,9 +365,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; } if (exception != null) { - listener.onTransformationError(exception); + listener.onTransformationError( + transformationResultBuilder.setTransformationException(exception).build(), exception); } else { - listener.onTransformationCompleted(checkNotNull(transformationResult)); + listener.onTransformationCompleted(transformationResultBuilder.build()); } } diff --git a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java index 249c261d68..986ba3b388 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerEndToEndTest.java @@ -337,9 +337,9 @@ public final class TransformerEndToEndTest { transformer.startTransformation(mediaItem, outputPath); TransformationException exception = TransformerTestRunner.runUntilError(transformer); - verify(mockListener1).onTransformationError(mediaItem, exception); - verify(mockListener2).onTransformationError(mediaItem, exception); - verify(mockListener3).onTransformationError(mediaItem, exception); + verify(mockListener1).onTransformationError(eq(mediaItem), any(), eq(exception)); + verify(mockListener2).onTransformationError(eq(mediaItem), any(), eq(exception)); + verify(mockListener3).onTransformationError(eq(mediaItem), any(), eq(exception)); } @Test diff --git a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerTestRunner.java b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerTestRunner.java index ee933c702f..c26eb10659 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerTestRunner.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/TransformerTestRunner.java @@ -85,7 +85,9 @@ public final class TransformerTestRunner { @Override public void onTransformationError( - MediaItem inputMediaItem, TransformationException exception) { + MediaItem inputMediaItem, + TransformationResult result, + TransformationException exception) { transformationException.set(exception); } });