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  */
16 
17 package com.android.camera.one.v2.core;
18 
19 import android.hardware.camera2.CameraAccessException;
20 import android.hardware.camera2.CameraCaptureSession;
21 import android.hardware.camera2.CaptureFailure;
22 import android.hardware.camera2.CaptureRequest;
23 import android.hardware.camera2.CaptureResult;
24 import android.hardware.camera2.TotalCaptureResult;
25 import android.os.Handler;
26 
27 import com.android.camera.one.v2.camera2proxy.CameraCaptureSessionClosedException;
28 import com.android.camera.one.v2.camera2proxy.CameraCaptureSessionProxy;
29 import com.android.camera.one.v2.camera2proxy.CaptureRequestBuilderProxy;
30 import com.google.common.annotations.VisibleForTesting;
31 
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36 
37 /**
38  * Like {@link android.hardware.camera2.CameraCaptureSession}, but takes
39  * {@link Request}s and dispatches to the appropriate {@link ResponseListener}
40  * on a per-request basis, instead of for every {@link CaptureRequest} submitted
41  * at the same time.
42  */
43 @VisibleForTesting
44 public class TagDispatchCaptureSession implements FrameServer.Session {
45     private static class CaptureCallback implements CameraCaptureSessionProxy.CaptureCallback {
46         private final Map<Object, ResponseListener> mListeners;
47 
48         /**
49          * @param listeners A map from tag objects to the listener to be invoked
50          *            for events related to the request with that tag.
51          */
CaptureCallback(Map<Object, ResponseListener> listeners)52         public CaptureCallback(Map<Object, ResponseListener> listeners) {
53             mListeners = new HashMap<>(listeners);
54         }
55 
56         @Override
onCaptureStarted(CameraCaptureSessionProxy session, CaptureRequest request, long timestamp, long frameNumber)57         public void onCaptureStarted(CameraCaptureSessionProxy session, CaptureRequest request,
58                 long timestamp, long frameNumber) {
59             Object tag = request.getTag();
60             mListeners.get(tag).onStarted(timestamp);
61         }
62 
63         @Override
onCaptureProgressed(CameraCaptureSessionProxy session, CaptureRequest request, CaptureResult partialResult)64         public void onCaptureProgressed(CameraCaptureSessionProxy session, CaptureRequest request,
65                 CaptureResult partialResult) {
66             Object tag = request.getTag();
67             mListeners.get(tag).onProgressed(partialResult);
68         }
69 
70         @Override
onCaptureCompleted(CameraCaptureSessionProxy session, CaptureRequest request, TotalCaptureResult result)71         public void onCaptureCompleted(CameraCaptureSessionProxy session, CaptureRequest request,
72                 TotalCaptureResult result) {
73             Object tag = request.getTag();
74             mListeners.get(tag).onCompleted(result);
75         }
76 
77         @Override
onCaptureFailed(CameraCaptureSessionProxy session, CaptureRequest request, CaptureFailure failure)78         public void onCaptureFailed(CameraCaptureSessionProxy session, CaptureRequest request,
79                 CaptureFailure failure) {
80             Object tag = request.getTag();
81             mListeners.get(tag).onFailed(failure);
82         }
83 
84         @Override
onCaptureSequenceAborted(CameraCaptureSessionProxy session, int sequenceId)85         public void onCaptureSequenceAborted(CameraCaptureSessionProxy session, int sequenceId) {
86             for (ResponseListener listener : mListeners.values()) {
87                 listener.onSequenceAborted(sequenceId);
88             }
89         }
90 
91         @Override
onCaptureSequenceCompleted(CameraCaptureSessionProxy session, int sequenceId, long frameNumber)92         public void onCaptureSequenceCompleted(CameraCaptureSessionProxy session, int sequenceId,
93                 long frameNumber) {
94             for (ResponseListener listener : mListeners.values()) {
95                 listener.onSequenceCompleted(sequenceId, frameNumber);
96             }
97         }
98     }
99 
100     private final CameraCaptureSessionProxy mCaptureSession;
101     private final Handler mCameraHandler;
102     private long mTagCounter;
103 
TagDispatchCaptureSession(CameraCaptureSessionProxy captureSession, Handler cameraHandler)104     public TagDispatchCaptureSession(CameraCaptureSessionProxy captureSession, Handler
105             cameraHandler) {
106         mCaptureSession = captureSession;
107         mCameraHandler = cameraHandler;
108         mTagCounter = 0;
109     }
110 
generateTag()111     private Object generateTag() {
112         Object tag = Long.valueOf(mTagCounter);
113         mTagCounter++;
114         return tag;
115     }
116 
117     /**
118      * Submits the given burst request to the underlying
119      * {@link CameraCaptureSessionProxy}.
120      * <p/>
121      * Note that the Tag associated with the {@link CaptureRequest} from each
122      * {@link Request} will be overwritten.
123      *
124      * @param burstRequests The list of {@link Request}s to send.
125      * @param requestType Whether the request should be sent as a repeating
126      *            request.
127      * @throws CameraAccessException See
128      *             {@link CameraCaptureSession#captureBurst} and
129      *             {@link CameraCaptureSession#setRepeatingBurst}.
130      * @throws InterruptedException if interrupted while waiting to allocate
131      *             resources necessary for each {@link Request}.
132      */
submitRequest(List<Request> burstRequests, FrameServer.RequestType requestType)133     public void submitRequest(List<Request> burstRequests, FrameServer.RequestType requestType)
134             throws
135             CameraAccessException, InterruptedException, CameraCaptureSessionClosedException,
136             ResourceAcquisitionFailedException {
137         try {
138             Map<Object, ResponseListener> tagListenerMap = new HashMap<Object, ResponseListener>();
139             List<CaptureRequest> captureRequests = new ArrayList<>(burstRequests.size());
140 
141             for (Request request : burstRequests) {
142                 Object tag = generateTag();
143 
144                 tagListenerMap.put(tag, request.getResponseListener());
145 
146                 CaptureRequestBuilderProxy builder = request.allocateCaptureRequest();
147                 builder.setTag(tag);
148                 captureRequests.add(builder.build());
149             }
150 
151             if (requestType == FrameServer.RequestType.REPEATING) {
152                 mCaptureSession.setRepeatingBurst(captureRequests, new
153                         CaptureCallback(tagListenerMap), mCameraHandler);
154             } else {
155                 mCaptureSession.captureBurst(captureRequests, new
156                         CaptureCallback(tagListenerMap), mCameraHandler);
157             }
158         } catch (Exception e) {
159             for (Request r : burstRequests) {
160                 r.abort();
161             }
162             throw e;
163         }
164     }
165 
close()166     public void close() {
167         // Do nothing.
168     }
169 }
170