Merge "Add APIs for streaming AD insertion"

This commit is contained in:
TreeHugger Robot
2022-12-21 04:29:35 +00:00
committed by Android (Google) Code Review
20 changed files with 509 additions and 6 deletions

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2022 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.tv;
parcelable AdBuffer;

View File

@@ -0,0 +1,163 @@
/*
* Copyright (C) 2022 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.tv;
import android.annotation.NonNull;
import android.media.MediaCodec.BufferFlag;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SharedMemory;
/**
* Buffer for advertisement data.
* @hide
*/
public class AdBuffer implements Parcelable {
private final int mId;
@NonNull
private final String mMimeType;
@NonNull
private final SharedMemory mBuffer;
private final int mOffset;
private final int mLength;
private final long mPresentationTimeUs;
private final int mFlags;
public AdBuffer(
int id,
@NonNull String mimeType,
@NonNull SharedMemory buffer,
int offset,
int length,
long presentationTimeUs,
@BufferFlag int flags) {
this.mId = id;
this.mMimeType = mimeType;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mimeType);
this.mBuffer = buffer;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, buffer);
this.mOffset = offset;
this.mLength = length;
this.mPresentationTimeUs = presentationTimeUs;
this.mFlags = flags;
}
/**
* Gets corresponding AD request ID.
*/
public int getId() {
return mId;
}
/**
* Gets the mime type of the data.
*/
@NonNull
public String getMimeType() {
return mMimeType;
}
/**
* Gets the shared memory which stores the data.
*/
@NonNull
public SharedMemory getSharedMemory() {
return mBuffer;
}
/**
* Gets the offset of the buffer.
*/
public int getOffset() {
return mOffset;
}
/**
* Gets the data length.
*/
public int getLength() {
return mLength;
}
/**
* Gets the presentation time in microseconds.
*/
public long getPresentationTimeUs() {
return mPresentationTimeUs;
}
/**
* Gets the flags.
*/
@BufferFlag
public int getFlags() {
return mFlags;
}
@Override
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
dest.writeInt(mId);
dest.writeString(mMimeType);
dest.writeTypedObject(mBuffer, flags);
dest.writeInt(mOffset);
dest.writeInt(mLength);
dest.writeLong(mPresentationTimeUs);
dest.writeInt(mFlags);
}
@Override
public int describeContents() {
return 0;
}
private AdBuffer(@NonNull Parcel in) {
int id = in.readInt();
String mimeType = in.readString();
SharedMemory buffer = (SharedMemory) in.readTypedObject(SharedMemory.CREATOR);
int offset = in.readInt();
int length = in.readInt();
long presentationTimeUs = in.readLong();
int flags = in.readInt();
this.mId = id;
this.mMimeType = mimeType;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mMimeType);
this.mBuffer = buffer;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mBuffer);
this.mOffset = offset;
this.mLength = length;
this.mPresentationTimeUs = presentationTimeUs;
this.mFlags = flags;
}
public static final @NonNull Parcelable.Creator<AdBuffer> CREATOR =
new Parcelable.Creator<AdBuffer>() {
@Override
public AdBuffer[] newArray(int size) {
return new AdBuffer[size];
}
@Override
public AdBuffer createFromParcel(Parcel in) {
return new AdBuffer(in);
}
};
}

View File

@@ -19,6 +19,7 @@ package android.media.tv;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
@@ -69,10 +70,25 @@ public final class AdRequest implements Parcelable {
private final long mEchoInterval;
private final String mMediaFileType;
private final Bundle mMetadata;
private final Uri mUri;
public AdRequest(int id, @RequestType int requestType,
@Nullable ParcelFileDescriptor fileDescriptor, long startTime, long stopTime,
long echoInterval, @Nullable String mediaFileType, @NonNull Bundle metadata) {
this(id, requestType, fileDescriptor, null, startTime, stopTime, echoInterval,
mediaFileType, metadata);
}
/** @hide */
public AdRequest(int id, @RequestType int requestType, @Nullable Uri uri, long startTime,
long stopTime, long echoInterval, @NonNull Bundle metadata) {
this(id, requestType, null, uri, startTime, stopTime, echoInterval, null, metadata);
}
private AdRequest(int id, @RequestType int requestType,
@Nullable ParcelFileDescriptor fileDescriptor, @Nullable Uri uri, long startTime,
long stopTime, long echoInterval, @Nullable String mediaFileType,
@NonNull Bundle metadata) {
mId = id;
mRequestType = requestType;
mFileDescriptor = fileDescriptor;
@@ -81,15 +97,23 @@ public final class AdRequest implements Parcelable {
mEchoInterval = echoInterval;
mMediaFileType = mediaFileType;
mMetadata = metadata;
mUri = uri;
}
private AdRequest(Parcel source) {
mId = source.readInt();
mRequestType = source.readInt();
if (source.readInt() != 0) {
int readInt = source.readInt();
if (readInt == 1) {
mFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(source);
mUri = null;
} else if (readInt == 2) {
String stringUri = source.readString();
mUri = stringUri == null ? null : Uri.parse(stringUri);
mFileDescriptor = null;
} else {
mFileDescriptor = null;
mUri = null;
}
mStartTime = source.readLong();
mStopTime = source.readLong();
@@ -117,13 +141,25 @@ public final class AdRequest implements Parcelable {
* Gets the file descriptor of the AD media.
*
* @return The file descriptor of the AD media. Can be {@code null} for
* {@link #REQUEST_TYPE_STOP}
* {@link #REQUEST_TYPE_STOP} or a URI is used.
*/
@Nullable
public ParcelFileDescriptor getFileDescriptor() {
return mFileDescriptor;
}
/**
* Gets the URI of the AD media.
*
* @return The URI of the AD media. Can be {@code null} for {@link #REQUEST_TYPE_STOP} or a file
* descriptor is used.
* @hide
*/
@Nullable
public Uri getUri() {
return mUri;
}
/**
* Gets the start time of the AD media in milliseconds.
* <p>0 means start immediately
@@ -189,6 +225,10 @@ public final class AdRequest implements Parcelable {
if (mFileDescriptor != null) {
dest.writeInt(1);
mFileDescriptor.writeToParcel(dest, flags);
} else if (mUri != null) {
dest.writeInt(2);
String stringUri = mUri.toString();
dest.writeString(stringUri);
} else {
dest.writeInt(0);
}

View File

@@ -34,7 +34,8 @@ public final class AdResponse implements Parcelable {
RESPONSE_TYPE_PLAYING,
RESPONSE_TYPE_FINISHED,
RESPONSE_TYPE_STOPPED,
RESPONSE_TYPE_ERROR
RESPONSE_TYPE_ERROR,
RESPONSE_TYPE_BUFFERING
})
public @interface ResponseType {}
@@ -42,6 +43,8 @@ public final class AdResponse implements Parcelable {
public static final int RESPONSE_TYPE_FINISHED = 2;
public static final int RESPONSE_TYPE_STOPPED = 3;
public static final int RESPONSE_TYPE_ERROR = 4;
/** @hide */
public static final int RESPONSE_TYPE_BUFFERING = 5;
public static final @NonNull Parcelable.Creator<AdResponse> CREATOR =
new Parcelable.Creator<AdResponse>() {

View File

@@ -17,6 +17,7 @@
package android.media.tv;
import android.content.ComponentName;
import android.media.tv.AdBuffer;
import android.media.tv.AdResponse;
import android.media.tv.AitInfo;
import android.media.tv.BroadcastInfoResponse;
@@ -59,4 +60,5 @@ oneway interface ITvInputClient {
// For ad response
void onAdResponse(in AdResponse response, int seq);
void onAdBufferConsumed(in AdBuffer buffer, int seq);
}

View File

@@ -20,6 +20,7 @@ import android.content.ComponentName;
import android.content.Intent;
import android.graphics.Rect;
import android.media.PlaybackParams;
import android.media.tv.AdBuffer;
import android.media.tv.AdRequest;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.DvbDeviceInfo;
@@ -110,6 +111,7 @@ interface ITvInputManager {
// For ad request
void requestAd(in IBinder sessionToken, in AdRequest request, int userId);
void notifyAdBuffer(in IBinder sessionToken, in AdBuffer buffer, int userId);
// For TV input hardware binding
List<TvInputHardwareInfo> getHardwareList();

View File

@@ -18,6 +18,7 @@ package android.media.tv;
import android.graphics.Rect;
import android.media.PlaybackParams;
import android.media.tv.AdBuffer;
import android.media.tv.AdRequest;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.TvTrackInfo;
@@ -71,4 +72,5 @@ oneway interface ITvInputSession {
// For ad request
void requestAd(in AdRequest request);
void notifyAdBuffer(in AdBuffer buffer);
}

View File

@@ -16,6 +16,7 @@
package android.media.tv;
import android.media.tv.AdBuffer;
import android.media.tv.AdResponse;
import android.media.tv.AitInfo;
import android.media.tv.BroadcastInfoResponse;
@@ -56,4 +57,5 @@ oneway interface ITvInputSessionCallback {
// For ad response
void onAdResponse(in AdResponse response);
void onAdBufferConsumed(in AdBuffer buffer);
}

View File

@@ -74,6 +74,7 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
private static final int DO_REMOVE_BROADCAST_INFO = 25;
private static final int DO_SET_IAPP_NOTIFICATION_ENABLED = 26;
private static final int DO_REQUEST_AD = 27;
private static final int DO_NOTIFY_AD_BUFFER = 28;
private final boolean mIsRecordingSession;
private final HandlerCaller mCaller;
@@ -224,6 +225,7 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
case DO_START_RECORDING: {
SomeArgs args = (SomeArgs) msg.obj;
mTvInputRecordingSessionImpl.startRecording((Uri) args.arg1, (Bundle) args.arg2);
args.recycle();
break;
}
case DO_STOP_RECORDING: {
@@ -254,6 +256,10 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
mTvInputSessionImpl.requestAd((AdRequest) msg.obj);
break;
}
case DO_NOTIFY_AD_BUFFER: {
mTvInputSessionImpl.notifyAdBuffer((AdBuffer) msg.obj);
break;
}
default: {
Log.w(TAG, "Unhandled message code: " + msg.what);
break;
@@ -424,6 +430,11 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_REQUEST_AD, request));
}
@Override
public void notifyAdBuffer(AdBuffer buffer) {
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_NOTIFY_AD_BUFFER, buffer));
}
private final class TvInputEventReceiver extends InputEventReceiver {
public TvInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);

View File

@@ -965,6 +965,19 @@ public final class TvInputManager {
});
}
}
void postAdBufferConsumed(AdBuffer buffer) {
if (mSession.mIAppNotificationEnabled) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mSession.getInteractiveAppSession() != null) {
mSession.getInteractiveAppSession().notifyAdBufferConsumed(buffer);
}
}
});
}
}
}
/**
@@ -1412,6 +1425,18 @@ public final class TvInputManager {
record.postAdResponse(response);
}
}
@Override
public void onAdBufferConsumed(AdBuffer buffer, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
if (record == null) {
Log.e(TAG, "Callback not found for seq " + seq);
return;
}
record.postAdBufferConsumed(buffer);
}
}
};
ITvInputManagerCallback managerCallback = new ITvInputManagerCallback.Stub() {
@Override
@@ -3204,6 +3229,21 @@ public final class TvInputManager {
}
}
/**
* Notifies when the advertisement buffer is filled and ready to be read.
*/
public void notifyAdBuffer(AdBuffer buffer) {
if (mToken == null) {
Log.w(TAG, "The session has been already released");
return;
}
try {
mService.notifyAdBuffer(mToken, buffer, mUserId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
private final class InputEventHandler extends Handler {
public static final int MSG_SEND_INPUT_EVENT = 1;
public static final int MSG_TIMEOUT_INPUT_EVENT = 2;

View File

@@ -913,6 +913,27 @@ public abstract class TvInputService extends Service {
});
}
/**
* Notifies the advertisement buffer is consumed.
* @hide
*/
public void notifyAdBufferConsumed(AdBuffer buffer) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@Override
public void run() {
try {
if (DEBUG) Log.d(TAG, "notifyAdBufferConsumed");
if (mSessionCallback != null) {
mSessionCallback.onAdBufferConsumed(buffer);
}
} catch (RemoteException e) {
Log.w(TAG, "error in notifyAdBufferConsumed", e);
}
}
});
}
private void notifyTimeShiftStartPositionChanged(final long timeMs) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@@ -1128,6 +1149,13 @@ public abstract class TvInputService extends Service {
public void onRequestAd(@NonNull AdRequest request) {
}
/**
* Called when advertisement buffer is ready.
* @hide
*/
public void onAdBuffer(AdBuffer buffer) {
}
/**
* Tunes to a given channel.
*
@@ -1753,6 +1781,10 @@ public abstract class TvInputService extends Service {
onRequestAd(request);
}
void notifyAdBuffer(AdBuffer buffer) {
onAdBuffer(buffer);
}
/**
* Takes care of dispatching incoming input events and tells whether the event was handled.
*/

View File

@@ -17,6 +17,7 @@
package android.media.tv.interactive;
import android.graphics.Rect;
import android.media.tv.AdBuffer;
import android.media.tv.AdRequest;
import android.media.tv.BroadcastInfoRequest;
import android.net.Uri;
@@ -37,6 +38,7 @@ oneway interface ITvInteractiveAppClient {
void onSessionStateChanged(int state, int err, int seq);
void onBiInteractiveAppCreated(in Uri biIAppUri, in String biIAppId, int seq);
void onTeletextAppStateChanged(int state, int seq);
void onAdBuffer(in AdBuffer buffer, int seq);
void onCommandRequest(in String cmdType, in Bundle parameters, int seq);
void onSetVideoBounds(in Rect rect, int seq);
void onRequestCurrentChannelUri(int seq);

View File

@@ -17,6 +17,7 @@
package android.media.tv.interactive;
import android.graphics.Rect;
import android.media.tv.AdBuffer;
import android.media.tv.AdResponse;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.TvTrackInfo;
@@ -71,6 +72,7 @@ interface ITvInteractiveAppManager {
void notifyBroadcastInfoResponse(in IBinder sessionToken, in BroadcastInfoResponse response,
int UserId);
void notifyAdResponse(in IBinder sessionToken, in AdResponse response, int UserId);
void notifyAdBufferConsumed(in IBinder sessionToken, in AdBuffer buffer, int userId);
void createMediaView(in IBinder sessionToken, in IBinder windowToken, in Rect frame,
int userId);

View File

@@ -19,6 +19,7 @@ package android.media.tv.interactive;
import android.graphics.Rect;
import android.media.tv.BroadcastInfoResponse;
import android.net.Uri;
import android.media.tv.AdBuffer;
import android.media.tv.AdResponse;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.TvTrackInfo;
@@ -59,6 +60,7 @@ oneway interface ITvInteractiveAppSession {
void dispatchSurfaceChanged(int format, int width, int height);
void notifyBroadcastInfoResponse(in BroadcastInfoResponse response);
void notifyAdResponse(in AdResponse response);
void notifyAdBufferConsumed(in AdBuffer buffer);
void createMediaView(in IBinder windowToken, in Rect frame);
void relayoutMediaView(in Rect frame);

View File

@@ -17,6 +17,7 @@
package android.media.tv.interactive;
import android.graphics.Rect;
import android.media.tv.AdBuffer;
import android.media.tv.AdRequest;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.interactive.ITvInteractiveAppSession;
@@ -36,6 +37,7 @@ oneway interface ITvInteractiveAppSessionCallback {
void onSessionStateChanged(int state, int err);
void onBiInteractiveAppCreated(in Uri biIAppUri, in String biIAppId);
void onTeletextAppStateChanged(int state);
void onAdBuffer(in AdBuffer buffer);
void onCommandRequest(in String cmdType, in Bundle parameters);
void onSetVideoBounds(in Rect rect);
void onRequestCurrentChannelUri();

View File

@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Rect;
import android.media.tv.AdBuffer;
import android.media.tv.AdResponse;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.TvContentRating;
@@ -83,6 +84,7 @@ public class ITvInteractiveAppSessionWrapper
private static final int DO_REMOVE_MEDIA_VIEW = 29;
private static final int DO_NOTIFY_RECORDING_STARTED = 30;
private static final int DO_NOTIFY_RECORDING_STOPPED = 31;
private static final int DO_NOTIFY_AD_BUFFER_CONSUMED = 32;
private final HandlerCaller mCaller;
private Session mSessionImpl;
@@ -253,6 +255,10 @@ public class ITvInteractiveAppSessionWrapper
mSessionImpl.removeMediaView(true);
break;
}
case DO_NOTIFY_AD_BUFFER_CONSUMED: {
mSessionImpl.notifyAdBufferConsumed((AdBuffer) msg.obj);
break;
}
default: {
Log.w(TAG, "Unhandled message code: " + msg.what);
break;
@@ -424,6 +430,11 @@ public class ITvInteractiveAppSessionWrapper
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_NOTIFY_AD_RESPONSE, response));
}
@Override
public void notifyAdBufferConsumed(AdBuffer buffer) {
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_NOTIFY_AD_BUFFER_CONSUMED, buffer));
}
@Override
public void createMediaView(IBinder windowToken, Rect frame) {
mCaller.executeOrSendMessage(

View File

@@ -23,6 +23,7 @@ import android.annotation.Nullable;
import android.annotation.SystemService;
import android.content.Context;
import android.graphics.Rect;
import android.media.tv.AdBuffer;
import android.media.tv.AdRequest;
import android.media.tv.AdResponse;
import android.media.tv.BroadcastInfoRequest;
@@ -558,6 +559,18 @@ public final class TvInteractiveAppManager {
record.postTeletextAppStateChanged(state);
}
}
@Override
public void onAdBuffer(AdBuffer buffer, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
if (record == null) {
Log.e(TAG, "Callback not found for seq " + seq);
return;
}
record.postAdBuffer(buffer);
}
}
};
ITvInteractiveAppManagerCallback managerCallback =
new ITvInteractiveAppManagerCallback.Stub() {
@@ -1277,6 +1290,21 @@ public final class TvInteractiveAppManager {
}
}
/**
* Notifies the advertisement buffer is consumed.
*/
public void notifyAdBufferConsumed(AdBuffer buffer) {
if (mToken == null) {
Log.w(TAG, "The session has been already released");
return;
}
try {
mService.notifyAdBufferConsumed(mToken, buffer, mUserId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Releases this session.
*/
@@ -1808,6 +1836,17 @@ public final class TvInteractiveAppManager {
}
});
}
void postAdBuffer(AdBuffer buffer) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mSession.getInputSession() != null) {
mSession.getInputSession().notifyAdBuffer(buffer);
}
}
});
}
}
/**

View File

@@ -30,6 +30,7 @@ import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.media.tv.AdBuffer;
import android.media.tv.AdRequest;
import android.media.tv.AdResponse;
import android.media.tv.BroadcastInfoRequest;
@@ -616,6 +617,13 @@ public abstract class TvInteractiveAppService extends Service {
public void onAdResponse(@NonNull AdResponse response) {
}
/**
* Called when an advertisement buffer is consumed.
* @hide
*/
public void onAdBufferConsumed(AdBuffer buffer) {
}
@Override
public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
return false;
@@ -1189,6 +1197,17 @@ public abstract class TvInteractiveAppService extends Service {
onAdResponse(response);
}
/**
* Calls {@link #onAdBufferConsumed}.
*/
void notifyAdBufferConsumed(AdBuffer buffer) {
if (DEBUG) {
Log.d(TAG,
"notifyAdBufferConsumed (buffer=" + buffer + ")");
}
onAdBufferConsumed(buffer);
}
/**
* Calls {@link #onRecordingStarted(String)}.
*/
@@ -1290,6 +1309,33 @@ public abstract class TvInteractiveAppService extends Service {
});
}
/**
* Notifies when the advertisement buffer is filled and ready to be read.
* @hide
*/
@CallSuper
public void notifyAdBuffer(AdBuffer buffer) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@Override
public void run() {
try {
if (DEBUG) {
Log.d(TAG,
"notifyAdBuffer(buffer=" + buffer + ")");
}
if (mSessionCallback != null) {
mSessionCallback.onAdBuffer(buffer);
}
} catch (RemoteException e) {
Log.w(TAG, "error in notifyAdBuffer", e);
}
}
});
}
/**
* Takes care of dispatching incoming input events and tells whether the event was handled.
*/

View File

@@ -44,6 +44,7 @@ import android.graphics.Rect;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.media.PlaybackParams;
import android.media.tv.AdBuffer;
import android.media.tv.AdRequest;
import android.media.tv.AdResponse;
import android.media.tv.AitInfo;
@@ -2520,7 +2521,30 @@ public final class TvInputManagerService extends SystemService {
}
} finally {
Binder.restoreCallingIdentity(identity);
};
}
}
@Override
public void notifyAdBuffer(
IBinder sessionToken, AdBuffer buffer, int userId) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int resolvedUserId = resolveCallingUserId(callingPid, callingUid,
userId, "notifyAdBuffer");
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
try {
SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
resolvedUserId);
getSessionLocked(sessionState).notifyAdBuffer(buffer);
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in notifyAdBuffer", e);
}
}
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
@@ -3624,7 +3648,7 @@ public final class TvInputManagerService extends SystemService {
}
@Override
public void onBroadcastInfoResponse (BroadcastInfoResponse response) {
public void onBroadcastInfoResponse(BroadcastInfoResponse response) {
synchronized (mLock) {
if (DEBUG) {
Slog.d(TAG, "onBroadcastInfoResponse()");
@@ -3641,7 +3665,7 @@ public final class TvInputManagerService extends SystemService {
}
@Override
public void onAdResponse (AdResponse response) {
public void onAdResponse(AdResponse response) {
synchronized (mLock) {
if (DEBUG) {
Slog.d(TAG, "onAdResponse()");
@@ -3656,6 +3680,24 @@ public final class TvInputManagerService extends SystemService {
}
}
}
@Override
public void onAdBufferConsumed(AdBuffer buffer) {
synchronized (mLock) {
if (DEBUG) {
Slog.d(TAG, "onAdBufferConsumed()");
}
if (mSessionState.session == null || mSessionState.client == null) {
return;
}
try {
mSessionState.client.onAdBufferConsumed(
buffer, mSessionState.seq);
} catch (RemoteException e) {
Slog.e(TAG, "error in onAdBufferConsumed", e);
}
}
}
}
@VisibleForTesting

View File

@@ -29,6 +29,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.graphics.Rect;
import android.media.tv.AdBuffer;
import android.media.tv.AdRequest;
import android.media.tv.AdResponse;
import android.media.tv.BroadcastInfoRequest;
@@ -1512,6 +1513,29 @@ public class TvInteractiveAppManagerService extends SystemService {
}
}
@Override
public void notifyAdBufferConsumed(
IBinder sessionToken, AdBuffer buffer, int userId) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
"notifyAdBufferConsumed");
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
try {
SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
resolvedUserId);
getSessionLocked(sessionState).notifyAdBufferConsumed(buffer);
} catch (RemoteException | SessionNotFoundException e) {
Slogf.e(TAG, "error in notifyAdBufferConsumed", e);
}
}
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public void registerCallback(final ITvInteractiveAppManagerCallback callback, int userId) {
int callingPid = Binder.getCallingPid();
@@ -2378,6 +2402,23 @@ public class TvInteractiveAppManagerService extends SystemService {
}
}
@Override
public void onAdBuffer(AdBuffer buffer) {
synchronized (mLock) {
if (DEBUG) {
Slogf.d(TAG, "onAdBuffer(buffer=" + buffer + ")");
}
if (mSessionState.mSession == null || mSessionState.mClient == null) {
return;
}
try {
mSessionState.mClient.onAdBuffer(buffer, mSessionState.mSeq);
} catch (RemoteException e) {
Slogf.e(TAG, "error in onAdBuffer", e);
}
}
}
@GuardedBy("mLock")
private boolean addSessionTokenToClientStateLocked(ITvInteractiveAppSession session) {
try {