Merge "transcoding: Add retry api."
This commit is contained in:
@@ -27325,6 +27325,12 @@ package android.media {
|
||||
field public static final android.media.MediaTimestamp TIMESTAMP_UNKNOWN;
|
||||
}
|
||||
|
||||
public class MediaTranscodingException extends java.lang.Exception {
|
||||
}
|
||||
|
||||
public static final class MediaTranscodingException.ServiceNotAvailableException extends android.media.MediaTranscodingException {
|
||||
}
|
||||
|
||||
public interface MicrophoneDirection {
|
||||
method public boolean setPreferredMicrophoneDirection(int);
|
||||
method public boolean setPreferredMicrophoneFieldDimension(@FloatRange(from=-1.0, to=1.0) float);
|
||||
|
||||
@@ -4363,7 +4363,7 @@ package android.media {
|
||||
}
|
||||
|
||||
public final class MediaTranscodeManager {
|
||||
method @NonNull public android.media.MediaTranscodeManager.TranscodingJob enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener) throws java.io.FileNotFoundException;
|
||||
method @NonNull public android.media.MediaTranscodeManager.TranscodingJob enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener) throws java.io.FileNotFoundException, android.media.MediaTranscodingException.ServiceNotAvailableException;
|
||||
field public static final int PRIORITY_REALTIME = 1; // 0x1
|
||||
field public static final int TRANSCODING_TYPE_VIDEO = 1; // 0x1
|
||||
}
|
||||
@@ -4378,7 +4378,6 @@ package android.media {
|
||||
method @IntRange(from=0, to=100) public int getProgress();
|
||||
method public int getResult();
|
||||
method public int getStatus();
|
||||
method public boolean retry();
|
||||
method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingJob.OnProgressUpdateListener);
|
||||
method public void setOnProgressUpdateListener(int, @NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingJob.OnProgressUpdateListener);
|
||||
field public static final int RESULT_CANCELED = 4; // 0x4
|
||||
|
||||
@@ -1817,7 +1817,7 @@ package android.media {
|
||||
}
|
||||
|
||||
public final class MediaTranscodeManager {
|
||||
method @NonNull public android.media.MediaTranscodeManager.TranscodingJob enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener) throws java.io.FileNotFoundException;
|
||||
method @NonNull public android.media.MediaTranscodeManager.TranscodingJob enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener) throws java.io.FileNotFoundException, android.media.MediaTranscodingException.ServiceNotAvailableException;
|
||||
field public static final int PRIORITY_REALTIME = 1; // 0x1
|
||||
field public static final int TRANSCODING_TYPE_VIDEO = 1; // 0x1
|
||||
}
|
||||
@@ -1832,7 +1832,6 @@ package android.media {
|
||||
method @IntRange(from=0, to=100) public int getProgress();
|
||||
method public int getResult();
|
||||
method public int getStatus();
|
||||
method public boolean retry();
|
||||
method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingJob.OnProgressUpdateListener);
|
||||
method public void setOnProgressUpdateListener(int, @NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingJob.OnProgressUpdateListener);
|
||||
field public static final int RESULT_CANCELED = 4; // 0x4
|
||||
|
||||
@@ -274,7 +274,7 @@ public final class MediaTranscodeManager {
|
||||
|
||||
private static IMediaTranscodingService getService(boolean retry) {
|
||||
int retryCount = !retry ? 1 : CONNECT_SERVICE_RETRY_COUNT;
|
||||
Log.i(TAG, "get service with rety " + retryCount);
|
||||
Log.i(TAG, "get service with retry " + retryCount);
|
||||
for (int count = 1; count <= retryCount; count++) {
|
||||
Log.d(TAG, "Trying to connect to service. Try count: " + count);
|
||||
IMediaTranscodingService service = IMediaTranscodingService.Stub.asInterface(
|
||||
@@ -356,7 +356,15 @@ public final class MediaTranscodeManager {
|
||||
for (TranscodingJob job : retryJobs) {
|
||||
// Notify the job failure if we fails to connect to the service or fail
|
||||
// to retry the job.
|
||||
if (!haveTranscodingClient || !job.retry()) {
|
||||
if (!haveTranscodingClient) {
|
||||
// TODO(hkuang): Return correct error code to the client.
|
||||
handleTranscodingFailed(job.getJobId(), 0 /*unused */);
|
||||
}
|
||||
|
||||
try {
|
||||
// Do not set hasRetried for retry initiated by MediaTranscodeManager.
|
||||
job.retryInternal(false /*setHasRetried*/);
|
||||
} catch (Exception re) {
|
||||
// TODO(hkuang): Return correct error code to the client.
|
||||
handleTranscodingFailed(job.getJobId(), 0 /*unused */);
|
||||
}
|
||||
@@ -1010,9 +1018,9 @@ public final class MediaTranscodeManager {
|
||||
@IntRange(from = 0, to = 100) int progress);
|
||||
}
|
||||
|
||||
private final ITranscodingClient mJobOwner;
|
||||
private final Executor mListenerExecutor;
|
||||
private final OnTranscodingFinishedListener mListener;
|
||||
private final MediaTranscodeManager mManager;
|
||||
private Executor mListenerExecutor;
|
||||
private OnTranscodingFinishedListener mListener;
|
||||
private int mJobId = -1;
|
||||
// Lock for internal state.
|
||||
private final Object mLock = new Object();
|
||||
@@ -1028,20 +1036,26 @@ public final class MediaTranscodeManager {
|
||||
private @Status int mStatus = STATUS_PENDING;
|
||||
@GuardedBy("mLock")
|
||||
private @Result int mResult = RESULT_NONE;
|
||||
@GuardedBy("mLock")
|
||||
private boolean mHasRetried = false;
|
||||
// The original request that associated with this job.
|
||||
private final TranscodingRequest mRequest;
|
||||
|
||||
private TranscodingJob(
|
||||
@NonNull ITranscodingClient jobOwner,
|
||||
@NonNull MediaTranscodeManager manager,
|
||||
@NonNull TranscodingRequest request,
|
||||
@NonNull TranscodingJobParcel parcel,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull OnTranscodingFinishedListener listener) {
|
||||
Objects.requireNonNull(jobOwner, "JobOwner must not be null");
|
||||
Objects.requireNonNull(parcel, "TranscodingJobParcel must not be null");
|
||||
Objects.requireNonNull(manager, "manager must not be null");
|
||||
Objects.requireNonNull(parcel, "parcel must not be null");
|
||||
Objects.requireNonNull(executor, "listenerExecutor must not be null");
|
||||
Objects.requireNonNull(listener, "listener must not be null");
|
||||
mJobOwner = jobOwner;
|
||||
mManager = manager;
|
||||
mJobId = parcel.jobId;
|
||||
mListenerExecutor = executor;
|
||||
mListener = listener;
|
||||
mRequest = request;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1085,14 +1099,61 @@ public final class MediaTranscodeManager {
|
||||
|
||||
/**
|
||||
* Resubmit the transcoding job to the service.
|
||||
* Note that only the job that fails or gets cancelled could be retried and each job could
|
||||
* be retried only once. After that, Client need to enqueue a new request if they want to
|
||||
* try again.
|
||||
*
|
||||
* @return true if successfully resubmit the job to the service. False otherwise.
|
||||
* @throws MediaTranscodingException.ServiceNotAvailableException if the service
|
||||
* is temporarily unavailable due to internal service rebooting. Client could retry
|
||||
* again after receiving this exception.
|
||||
* @throws UnsupportedOperationException if the retry could not be fulfilled.
|
||||
* @hide
|
||||
*/
|
||||
public boolean retry() {
|
||||
public void retry() throws MediaTranscodingException.ServiceNotAvailableException {
|
||||
retryInternal(true /*setHasRetried*/);
|
||||
}
|
||||
|
||||
// TODO(hkuang): Add more test for it.
|
||||
private void retryInternal(boolean setHasRetried)
|
||||
throws MediaTranscodingException.ServiceNotAvailableException {
|
||||
synchronized (mLock) {
|
||||
// TODO(hkuang): Implement this.
|
||||
if (mStatus == STATUS_PENDING || mStatus == STATUS_RUNNING) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Failed to retry as job is in processing");
|
||||
}
|
||||
|
||||
if (mHasRetried) {
|
||||
throw new UnsupportedOperationException("Job has been retried already");
|
||||
}
|
||||
|
||||
// Get the client interface.
|
||||
ITranscodingClient client = mManager.getTranscodingClient();
|
||||
if (client == null) {
|
||||
throw new MediaTranscodingException.ServiceNotAvailableException(
|
||||
"Service rebooting. Try again later");
|
||||
}
|
||||
|
||||
synchronized (mManager.mPendingTranscodingJobs) {
|
||||
try {
|
||||
// Submits the request to MediaTranscoding service.
|
||||
TranscodingJobParcel jobParcel = new TranscodingJobParcel();
|
||||
if (!client.submitRequest(mRequest.writeToParcel(), jobParcel)) {
|
||||
mHasRetried = true;
|
||||
throw new UnsupportedOperationException("Failed to enqueue request");
|
||||
}
|
||||
|
||||
// Replace the old job id wit the new one.
|
||||
mJobId = jobParcel.jobId;
|
||||
// Adds the new job back into pending jobs.
|
||||
mManager.mPendingTranscodingJobs.put(mJobId, this);
|
||||
} catch (RemoteException re) {
|
||||
throw new MediaTranscodingException.ServiceNotAvailableException(
|
||||
"Failed to resubmit request to Transcoding service");
|
||||
}
|
||||
mStatus = STATUS_PENDING;
|
||||
mHasRetried = setHasRetried ? true : false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1105,7 +1166,11 @@ public final class MediaTranscodeManager {
|
||||
// Check if the job is finished already.
|
||||
if (mStatus != STATUS_FINISHED) {
|
||||
try {
|
||||
mJobOwner.cancelJob(mJobId);
|
||||
ITranscodingClient client = mManager.getTranscodingClient();
|
||||
// The client may be gone.
|
||||
if (client != null) {
|
||||
client.cancelJob(mJobId);
|
||||
}
|
||||
} catch (RemoteException re) {
|
||||
//TODO(hkuang): Find out what to do if failing to cancel the job.
|
||||
Log.e(TAG, "Failed to cancel the job due to exception: " + re);
|
||||
@@ -1173,6 +1238,12 @@ public final class MediaTranscodeManager {
|
||||
}
|
||||
}
|
||||
|
||||
private ITranscodingClient getTranscodingClient() {
|
||||
synchronized (mLock) {
|
||||
return mTranscodingClient;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues a TranscodingRequest for execution.
|
||||
* <p> Upon successfully accepting the request, MediaTranscodeManager will return a
|
||||
@@ -1185,13 +1256,17 @@ public final class MediaTranscodeManager {
|
||||
* @return A TranscodingJob for this operation.
|
||||
* @throws FileNotFoundException if the source Uri or destination Uri could not be opened.
|
||||
* @throws UnsupportedOperationException if the request could not be fulfilled.
|
||||
* @throws MediaTranscodingException.ServiceNotAvailableException if the service
|
||||
* is temporarily unavailable due to internal service rebooting. Client could retry
|
||||
* again after receiving this exception.
|
||||
*/
|
||||
@NonNull
|
||||
public TranscodingJob enqueueRequest(
|
||||
@NonNull TranscodingRequest transcodingRequest,
|
||||
@NonNull @CallbackExecutor Executor listenerExecutor,
|
||||
@NonNull OnTranscodingFinishedListener listener)
|
||||
throws FileNotFoundException {
|
||||
throws FileNotFoundException,
|
||||
MediaTranscodingException.ServiceNotAvailableException {
|
||||
Log.i(TAG, "enqueueRequest called.");
|
||||
Objects.requireNonNull(transcodingRequest, "transcodingRequest must not be null");
|
||||
Objects.requireNonNull(listenerExecutor, "listenerExecutor must not be null");
|
||||
@@ -1208,7 +1283,14 @@ public final class MediaTranscodeManager {
|
||||
synchronized (mPendingTranscodingJobs) {
|
||||
synchronized (mLock) {
|
||||
if (mTranscodingClient == null) {
|
||||
// TODO(hkuang): Handle the case if client is temporarily unavailable.
|
||||
// Try to register with the service again.
|
||||
IMediaTranscodingService service = getService(false /*retry*/);
|
||||
mTranscodingClient = registerClient(service);
|
||||
// If still fails, throws an exception to tell client to try later.
|
||||
if (mTranscodingClient == null) {
|
||||
throw new MediaTranscodingException.ServiceNotAvailableException(
|
||||
"Service rebooting. Try again later");
|
||||
}
|
||||
}
|
||||
|
||||
if (!mTranscodingClient.submitRequest(requestParcel, jobParcel)) {
|
||||
@@ -1218,7 +1300,8 @@ public final class MediaTranscodeManager {
|
||||
|
||||
// Wraps the TranscodingJobParcel into a TranscodingJob and returns it to client for
|
||||
// tracking.
|
||||
TranscodingJob job = new TranscodingJob(mTranscodingClient, jobParcel,
|
||||
TranscodingJob job = new TranscodingJob(this, transcodingRequest,
|
||||
jobParcel,
|
||||
listenerExecutor,
|
||||
listener);
|
||||
|
||||
|
||||
38
media/java/android/media/MediaTranscodingException.java
Normal file
38
media/java/android/media/MediaTranscodingException.java
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.media;
|
||||
|
||||
/**
|
||||
* Base class for MediaTranscoding exceptions
|
||||
*/
|
||||
public class MediaTranscodingException extends Exception {
|
||||
private MediaTranscodingException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception thrown when the service is rebooting and MediaTranscodeManager is temporarily
|
||||
* unavailable for accepting new request. It's likely that retrying will be successful.
|
||||
*/
|
||||
public static final class ServiceNotAvailableException extends
|
||||
MediaTranscodingException {
|
||||
/** @hide */
|
||||
public ServiceNotAvailableException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import android.media.MediaFormat;
|
||||
import android.media.MediaTranscodeManager;
|
||||
import android.media.MediaTranscodeManager.TranscodingJob;
|
||||
import android.media.MediaTranscodeManager.TranscodingRequest;
|
||||
import android.media.MediaTranscodingException;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.FileUtils;
|
||||
@@ -250,6 +251,27 @@ public class MediaTranscodeManagerDiedTest
|
||||
TRANSCODE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
assertTrue("Invalid job status", job.getStatus() == TranscodingJob.STATUS_FINISHED);
|
||||
assertTrue("Invalid job result", job.getResult()== TranscodingJob.RESULT_ERROR);
|
||||
|
||||
|
||||
boolean retryJob = false;
|
||||
// Wait till service is available again.
|
||||
Log.d(TAG, "Retry the failed transcoding job");
|
||||
while (!retryJob) {
|
||||
try {
|
||||
job.retry();
|
||||
// Break out when job retry succeeds.
|
||||
break;
|
||||
} catch (MediaTranscodingException.ServiceNotAvailableException ex) {
|
||||
// Sleep for 10 milliseconds to wait.
|
||||
Thread.sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
finishedOnTime = transcodeCompleteSemaphore.tryAcquire(
|
||||
TRANSCODE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
// Check the make sure job is successfully finished after retry.
|
||||
assertTrue("Invalid job status", job.getStatus() == TranscodingJob.STATUS_FINISHED);
|
||||
assertTrue("Invalid job result", job.getResult() == TranscodingJob.RESULT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.media.MediaFormat;
|
||||
import android.media.MediaTranscodeManager;
|
||||
import android.media.MediaTranscodeManager.TranscodingJob;
|
||||
import android.media.MediaTranscodeManager.TranscodingRequest;
|
||||
import android.media.MediaTranscodingException;
|
||||
import android.net.Uri;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import android.util.Log;
|
||||
@@ -101,7 +102,8 @@ public class MediaTranscodingBenchmark
|
||||
* Transcode the sourceFileName to destinationFileName with LOOP_COUNT.
|
||||
*/
|
||||
private void transcode(final String sourceFileName, final String destinationFileName)
|
||||
throws IOException, InterruptedException {
|
||||
throws IOException, InterruptedException,
|
||||
MediaTranscodingException.ServiceNotAvailableException {
|
||||
AtomicLong totalTimeMs = new AtomicLong();
|
||||
AtomicLong transcodingTime = new AtomicLong();
|
||||
Uri srcUri = getUri(sourceFileName);
|
||||
|
||||
@@ -27138,6 +27138,12 @@ package android.media {
|
||||
field public static final android.media.MediaTimestamp TIMESTAMP_UNKNOWN;
|
||||
}
|
||||
|
||||
public class MediaTranscodingException extends java.lang.Exception {
|
||||
}
|
||||
|
||||
public static final class MediaTranscodingException.ServiceNotAvailableException extends android.media.MediaTranscodingException {
|
||||
}
|
||||
|
||||
public interface MicrophoneDirection {
|
||||
method public boolean setPreferredMicrophoneDirection(int);
|
||||
method public boolean setPreferredMicrophoneFieldDimension(@FloatRange(from=-1.0, to=1.0) float);
|
||||
|
||||
@@ -4303,7 +4303,7 @@ package android.media {
|
||||
}
|
||||
|
||||
public final class MediaTranscodeManager {
|
||||
method @NonNull public android.media.MediaTranscodeManager.TranscodingJob enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener) throws java.io.FileNotFoundException;
|
||||
method @NonNull public android.media.MediaTranscodeManager.TranscodingJob enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener) throws java.io.FileNotFoundException, android.media.MediaTranscodingException.ServiceNotAvailableException;
|
||||
field public static final int PRIORITY_REALTIME = 1; // 0x1
|
||||
field public static final int TRANSCODING_TYPE_VIDEO = 1; // 0x1
|
||||
}
|
||||
@@ -4318,7 +4318,6 @@ package android.media {
|
||||
method @IntRange(from=0, to=100) public int getProgress();
|
||||
method public int getResult();
|
||||
method public int getStatus();
|
||||
method public boolean retry();
|
||||
method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingJob.OnProgressUpdateListener);
|
||||
method public void setOnProgressUpdateListener(int, @NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingJob.OnProgressUpdateListener);
|
||||
field public static final int RESULT_CANCELED = 4; // 0x4
|
||||
|
||||
Reference in New Issue
Block a user