RequestQueue.java revision e663cb77281c4c76241b820f6126543f1c2d859f
1/*
2 * Copyright (C) 2014 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 */
16package android.hardware.camera2.legacy;
17
18import android.hardware.camera2.CaptureRequest;
19import android.hardware.camera2.utils.LongParcelable;
20import android.util.Log;
21import android.util.Pair;
22
23import java.util.ArrayDeque;
24import java.util.List;
25
26/**
27 * A queue of bursts of requests.
28 *
29 * <p>This queue maintains the count of frames that have been produced, and is thread safe.</p>
30 */
31public class RequestQueue {
32    private static final String TAG = "RequestQueue";
33
34    private static final long INVALID_FRAME = -1;
35
36    private BurstHolder mRepeatingRequest = null;
37    private final ArrayDeque<BurstHolder> mRequestQueue = new ArrayDeque<BurstHolder>();
38
39    private long mCurrentFrameNumber = 0;
40    private long mCurrentRepeatingFrameNumber = INVALID_FRAME;
41    private int mCurrentRequestId = 0;
42
43    public RequestQueue() {}
44
45    /**
46     * Return and remove the next burst on the queue.
47     *
48     * <p>If a repeating burst is returned, it will not be removed.</p>
49     *
50     * @return a pair containing the next burst and the current frame number, or null if none exist.
51     */
52    public synchronized Pair<BurstHolder, Long> getNext() {
53        BurstHolder next = mRequestQueue.poll();
54        if (next == null && mRepeatingRequest != null) {
55            next = mRepeatingRequest;
56            mCurrentRepeatingFrameNumber = mCurrentFrameNumber +
57                    next.getNumberOfRequests();
58        }
59
60        if (next == null) {
61            return null;
62        }
63
64        Pair<BurstHolder, Long> ret =  new Pair<BurstHolder, Long>(next, mCurrentFrameNumber);
65        mCurrentFrameNumber += next.getNumberOfRequests();
66        return ret;
67    }
68
69    /**
70     * Cancel a repeating request.
71     *
72     * @param requestId the id of the repeating request to cancel.
73     * @return the last frame to be returned from the HAL for the given repeating request, or
74     *          {@code INVALID_FRAME} if none exists.
75     */
76    public synchronized long stopRepeating(int requestId) {
77        long ret = INVALID_FRAME;
78        if (mRepeatingRequest != null && mRepeatingRequest.getRequestId() == requestId) {
79            mRepeatingRequest = null;
80            ret = (mCurrentRepeatingFrameNumber == INVALID_FRAME) ? INVALID_FRAME :
81                    mCurrentRepeatingFrameNumber - 1;
82            mCurrentRepeatingFrameNumber = INVALID_FRAME;
83            Log.i(TAG, "Repeating capture request cancelled.");
84        } else {
85            Log.e(TAG, "cancel failed: no repeating request exists for request id: " + requestId);
86        }
87        return ret;
88    }
89
90    /**
91     * Cancel a repeating request.
92     *
93     * @return the last frame to be returned from the HAL for the given repeating request, or
94     *          {@code INVALID_FRAME} if none exists.
95     */
96    public synchronized long stopRepeating() {
97        if (mRepeatingRequest == null) {
98            Log.e(TAG, "cancel failed: no repeating request exists.");
99            return INVALID_FRAME;
100        }
101        return stopRepeating(mRepeatingRequest.getRequestId());
102    }
103
104    /**
105     * Add a the given burst to the queue.
106     *
107     * <p>If the burst is repeating, replace the current repeating burst.</p>
108     *
109     * @param requests the burst of requests to add to the queue.
110     * @param repeating true if the burst is repeating.
111     * @param frameNumber an output argument that contains either the frame number of the last frame
112     *                    that will be returned for this request, or the frame number of the last
113     *                    frame that will be returned for the current repeating request if this
114     *                    burst is set to be repeating.
115     * @return the request id.
116     */
117    public synchronized int submit(List<CaptureRequest> requests, boolean repeating,
118            /*out*/LongParcelable frameNumber) {
119        int requestId = mCurrentRequestId++;
120        BurstHolder burst = new BurstHolder(requestId, repeating, requests);
121        long ret = INVALID_FRAME;
122        if (burst.isRepeating()) {
123            Log.i(TAG, "Repeating capture request set.");
124            if (mRepeatingRequest != null) {
125                ret = (mCurrentRepeatingFrameNumber == INVALID_FRAME) ? INVALID_FRAME :
126                        mCurrentRepeatingFrameNumber - 1;
127            }
128            mCurrentRepeatingFrameNumber = INVALID_FRAME;
129            mRepeatingRequest = burst;
130        } else {
131            mRequestQueue.offer(burst);
132            ret = calculateLastFrame(burst.getRequestId());
133        }
134        frameNumber.setNumber(ret);
135        return requestId;
136    }
137
138    private long calculateLastFrame(int requestId) {
139        long total = mCurrentFrameNumber;
140        for (BurstHolder b : mRequestQueue) {
141            total += b.getNumberOfRequests();
142            if (b.getRequestId() == requestId) {
143                return total - 1;
144            }
145        }
146        throw new IllegalStateException(
147                "At least one request must be in the queue to calculate frame number");
148    }
149
150}
151