• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 The Android Open Source Project
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 android.media.tv.tuner.dvr;
18 
19 import android.annotation.BytesLong;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.SystemApi;
23 import android.media.tv.tuner.Tuner;
24 import android.media.tv.tuner.Tuner.Result;
25 import android.media.tv.tuner.TunerUtils;
26 import android.media.tv.tuner.filter.Filter;
27 import android.os.ParcelFileDescriptor;
28 import android.os.Process;
29 import android.util.Log;
30 
31 import com.android.internal.util.FrameworkStatsLog;
32 
33 import java.lang.annotation.Retention;
34 import java.lang.annotation.RetentionPolicy;
35 import java.util.concurrent.Executor;
36 
37 /**
38  * Digital Video Record (DVR) class which provides playback control on Demux's input buffer.
39  *
40  * <p>It's used to play recorded programs.
41  *
42  * @hide
43  */
44 @SystemApi
45 public class DvrPlayback implements AutoCloseable {
46 
47 
48     /** @hide */
49     @Retention(RetentionPolicy.SOURCE)
50     @IntDef(prefix = "PLAYBACK_STATUS_",
51             value = {PLAYBACK_STATUS_EMPTY, PLAYBACK_STATUS_ALMOST_EMPTY,
52                     PLAYBACK_STATUS_ALMOST_FULL, PLAYBACK_STATUS_FULL})
53     @interface PlaybackStatus {}
54 
55     /**
56      * The space of the playback is empty.
57      */
58     public static final int PLAYBACK_STATUS_EMPTY =
59             android.hardware.tv.tuner.PlaybackStatus.SPACE_EMPTY;
60     /**
61      * The space of the playback is almost empty.
62      *
63      * <p> the threshold is set in {@link DvrSettings}.
64      */
65     public static final int PLAYBACK_STATUS_ALMOST_EMPTY =
66             android.hardware.tv.tuner.PlaybackStatus.SPACE_ALMOST_EMPTY;
67     /**
68      * The space of the playback is almost full.
69      *
70      * <p> the threshold is set in {@link DvrSettings}.
71      */
72     public static final int PLAYBACK_STATUS_ALMOST_FULL =
73             android.hardware.tv.tuner.PlaybackStatus.SPACE_ALMOST_FULL;
74     /**
75      * The space of the playback is full.
76      */
77     public static final int PLAYBACK_STATUS_FULL =
78             android.hardware.tv.tuner.PlaybackStatus.SPACE_FULL;
79 
80     private static final String TAG = "TvTunerPlayback";
81 
82     private long mNativeContext;
83     private OnPlaybackStatusChangedListener mListener;
84     private Executor mExecutor;
85     private int mUserId;
86     private static int sInstantId = 0;
87     private int mSegmentId = 0;
88     private int mUnderflow;
89     private final Object mListenerLock = new Object();
90 
nativeAttachFilter(Filter filter)91     private native int nativeAttachFilter(Filter filter);
nativeDetachFilter(Filter filter)92     private native int nativeDetachFilter(Filter filter);
nativeConfigureDvr(DvrSettings settings)93     private native int nativeConfigureDvr(DvrSettings settings);
nativeStartDvr()94     private native int nativeStartDvr();
nativeStopDvr()95     private native int nativeStopDvr();
nativeFlushDvr()96     private native int nativeFlushDvr();
nativeClose()97     private native int nativeClose();
nativeSetFileDescriptor(int fd)98     private native void nativeSetFileDescriptor(int fd);
nativeRead(long size)99     private native long nativeRead(long size);
nativeRead(byte[] bytes, long offset, long size)100     private native long nativeRead(byte[] bytes, long offset, long size);
nativeSeek(long pos)101     private native long nativeSeek(long pos);
102 
DvrPlayback()103     private DvrPlayback() {
104         mUserId = Process.myUid();
105         mSegmentId = (sInstantId & 0x0000ffff) << 16;
106         sInstantId++;
107     }
108 
109     /** @hide */
setListener( @onNull Executor executor, @NonNull OnPlaybackStatusChangedListener listener)110     public void setListener(
111             @NonNull Executor executor, @NonNull OnPlaybackStatusChangedListener listener) {
112         synchronized (mListenerLock) {
113             mExecutor = executor;
114             mListener = listener;
115         }
116     }
117 
onPlaybackStatusChanged(int status)118     private void onPlaybackStatusChanged(int status) {
119         if (status == PLAYBACK_STATUS_EMPTY) {
120             mUnderflow++;
121         }
122         synchronized (mListenerLock) {
123             if (mExecutor != null && mListener != null) {
124                 mExecutor.execute(() -> {
125                     synchronized (mListenerLock) {
126                         if (mListener != null) {
127                             mListener.onPlaybackStatusChanged(status);
128                         }
129                     }
130                 });
131             }
132         }
133     }
134 
135 
136     /**
137      * Attaches a filter to DVR interface for playback.
138      *
139      * @deprecated attaching filters is not valid in Dvr Playback use case. This API is a no-op.
140      *             Filters opened by {@link Tuner#openFilter} are used for DVR playback.
141      *
142      * @param filter the filter to be attached.
143      * @return result status of the operation.
144      */
145     @Result
146     @Deprecated
attachFilter(@onNull Filter filter)147     public int attachFilter(@NonNull Filter filter) {
148         // no-op
149         return Tuner.RESULT_UNAVAILABLE;
150     }
151 
152     /**
153      * Detaches a filter from DVR interface.
154      *
155      * @deprecated detaching filters is not valid in Dvr Playback use case. This API is a no-op.
156      *             Filters opened by {@link Tuner#openFilter} are used for DVR playback.
157      *
158      * @param filter the filter to be detached.
159      * @return result status of the operation.
160      */
161     @Result
162     @Deprecated
detachFilter(@onNull Filter filter)163     public int detachFilter(@NonNull Filter filter) {
164         // no-op
165         return Tuner.RESULT_UNAVAILABLE;
166     }
167 
168     /**
169      * Configures the DVR.
170      *
171      * @param settings the settings of the DVR interface.
172      * @return result status of the operation.
173      */
174     @Result
configure(@onNull DvrSettings settings)175     public int configure(@NonNull DvrSettings settings) {
176         return nativeConfigureDvr(settings);
177     }
178 
179     /**
180      * Starts DVR.
181      *
182      * <p>Starts consuming playback data or producing data for recording.
183      *
184      * @return result status of the operation.
185      */
186     @Result
start()187     public int start() {
188         mSegmentId =  (mSegmentId & 0xffff0000) | (((mSegmentId & 0x0000ffff) + 1) & 0x0000ffff);
189         mUnderflow = 0;
190         Log.d(TAG, "Write Stats Log for Playback.");
191         FrameworkStatsLog
192                 .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
193                     FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__PLAYBACK,
194                     FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STARTED, mSegmentId, 0);
195         return nativeStartDvr();
196     }
197 
198     /**
199      * Stops DVR.
200      *
201      * <p>Stops consuming playback data or producing data for recording.
202      * <p>Does nothing if the filter is stopped or not started.</p>
203      *
204      * @return result status of the operation.
205      */
206     @Result
stop()207     public int stop() {
208         Log.d(TAG, "Write Stats Log for Playback.");
209         FrameworkStatsLog
210                 .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
211                     FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__PLAYBACK,
212                     FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STOPPED, mSegmentId, mUnderflow);
213         return nativeStopDvr();
214     }
215 
216     /**
217      * Flushed DVR data.
218      *
219      * <p>The data in DVR buffer is cleared.
220      *
221      * @return result status of the operation.
222      */
223     @Result
flush()224     public int flush() {
225         return nativeFlushDvr();
226     }
227 
228     /**
229      * Closes the DVR instance to release resources.
230      */
231     @Override
close()232     public void close() {
233         int res = nativeClose();
234         if (res != Tuner.RESULT_SUCCESS) {
235             TunerUtils.throwExceptionForResult(res, "failed to close DVR playback");
236         }
237     }
238 
239     /**
240      * Sets file descriptor to read data.
241      *
242      * <p>When a read operation of the filter object is happening, this method should not be
243      * called.
244      *
245      * @param fd the file descriptor to read data.
246      * @see #read(long)
247      * @see #seek(long)
248      */
setFileDescriptor(@onNull ParcelFileDescriptor fd)249     public void setFileDescriptor(@NonNull ParcelFileDescriptor fd) {
250         nativeSetFileDescriptor(fd.getFd());
251     }
252 
253     /**
254      * Reads data from the file for DVR playback.
255      *
256      * @param size the maximum number of bytes to read.
257      * @return the number of bytes read.
258      */
259     @BytesLong
read(@ytesLong long size)260     public long read(@BytesLong long size) {
261         return nativeRead(size);
262     }
263 
264     /**
265      * Reads data from the buffer for DVR playback.
266      *
267      * @param buffer the byte array where DVR reads data from.
268      * @param offset the index of the first byte in {@code buffer} to read.
269      * @param size the maximum number of bytes to read.
270      * @return the number of bytes read.
271      */
272     @BytesLong
read(@onNull byte[] buffer, @BytesLong long offset, @BytesLong long size)273     public long read(@NonNull byte[] buffer, @BytesLong long offset, @BytesLong long size) {
274         if (size + offset > buffer.length) {
275             throw new ArrayIndexOutOfBoundsException(
276                     "Array length=" + buffer.length + ", offset=" + offset + ", size=" + size);
277         }
278         return nativeRead(buffer, offset, size);
279     }
280 
281     /**
282      * Sets the file pointer offset of the file descriptor.
283      *
284      * @param position the offset position, measured in bytes from the beginning of the file.
285      * @return the new offset position. On error, {@code -1} is returned.
286      */
287     @BytesLong
seek(@ytesLong long position)288     public long seek(@BytesLong long position) {
289         return nativeSeek(position);
290     }
291 }
292