1e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall/*
2e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall * Copyright (C) 2015 The Android Open Source Project
3e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall *
4e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall * Licensed under the Apache License, Version 2.0 (the "License");
5e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall * you may not use this file except in compliance with the License.
6e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall * You may obtain a copy of the License at
7e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall *
8e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall *      http://www.apache.org/licenses/LICENSE-2.0
9e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall *
10e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall * Unless required by applicable law or agreed to in writing, software
11e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall * distributed under the License is distributed on an "AS IS" BASIS,
12e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall * See the License for the specific language governing permissions and
14e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall * limitations under the License.
15e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall */
16e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall
17e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lallpackage com.android.camera.one.v2.core;
18e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall
19e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lallimport android.hardware.camera2.CameraAccessException;
20e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall
21e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lallimport com.android.camera.async.ConcurrentState;
22e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lallimport com.android.camera.async.Observable;
23e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lallimport com.android.camera.async.SafeCloseable;
24e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lallimport com.android.camera.one.v2.camera2proxy.CameraCaptureSessionClosedException;
25e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall
26e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lallimport java.util.List;
27e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lallimport java.util.concurrent.Executor;
28e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lallimport java.util.concurrent.atomic.AtomicBoolean;
29ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lallimport java.util.concurrent.atomic.AtomicInteger;
30e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall
31e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lallimport javax.annotation.Nonnull;
32e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lallimport javax.annotation.Nullable;
33e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lallimport javax.annotation.ParametersAreNonnullByDefault;
34e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall
35e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall/**
36e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall * Decorates a {@link FrameServer} to enable listening for changes to
37e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall * availability (whether or not an exclusive session can likely be acquired
38e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall * immediately).
39e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall */
40e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall@ParametersAreNonnullByDefault
41e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lallfinal class ObservableFrameServer implements FrameServer, Observable<Boolean> {
42ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall    /**
43ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall     * The total number of clients which either have an exclusive Session or are
44ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall     * waiting to acquire one. When this is positive, the frame server is "not
45ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall     * available".
46ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall     */
47ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall    private final AtomicInteger mClientCount;
48e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    private final ConcurrentState<Boolean> mAvailability;
49e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    private final FrameServer mDelegate;
50e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall
51e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    private class SessionImpl implements Session {
52e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall        private final AtomicBoolean mClosed;
53e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall        private final Session mDelegate;
54e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall
55e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall        private SessionImpl(Session delegate) {
56e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall            mClosed = new AtomicBoolean(false);
57e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall            mDelegate = delegate;
58e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall        }
59e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall
60e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall        @Override
61e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall        public void submitRequest(List<Request> burstRequests, RequestType type)
62e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall                throws CameraAccessException, InterruptedException,
63e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall                CameraCaptureSessionClosedException, ResourceAcquisitionFailedException {
64e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall            mDelegate.submitRequest(burstRequests, type);
65e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall        }
66e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall
67e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall        @Override
68e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall        public void close() {
69e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall            if (!mClosed.getAndSet(true)) {
70ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall                int clients = mClientCount.decrementAndGet();
71ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall                mAvailability.update(clients == 0);
72e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall                mDelegate.close();
73e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall            }
74e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall        }
75e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    }
76e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall
77e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    public ObservableFrameServer(FrameServer delegate) {
78e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall        mDelegate = delegate;
79ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall        mClientCount = new AtomicInteger(0);
80e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall        mAvailability = new ConcurrentState<>(true);
81e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    }
82e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall
83e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    @Nonnull
84e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    @Override
85e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    public Session createExclusiveSession() throws InterruptedException {
86ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall        int clients = mClientCount.incrementAndGet();
87ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall        mAvailability.update(clients == 0);
88ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall        try {
89ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall            // Ownership of the incremented value in mClientCount is passed to
90ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall            // the session, which is responsible for decrementing it later.
91ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall            Session session = mDelegate.createExclusiveSession();
92ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall            return new SessionImpl(session);
93ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall        } catch (InterruptedException e) {
94ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall            // If no session was acquired, we still "own" the increment of
95ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall            // mClientCount and must decrement it here.
96ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall            clients = mClientCount.decrementAndGet();
97ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall            mAvailability.update(clients == 0);
98ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall            throw e;
99ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall        }
100e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    }
101e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall
102e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    @Nullable
103e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    @Override
104e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    public Session tryCreateExclusiveSession() {
105e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall        Session session = mDelegate.tryCreateExclusiveSession();
106e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall        if (session == null) {
107e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall            return null;
108e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall        } else {
109ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall            int clients = mClientCount.incrementAndGet();
110ccb0c17a104801a994c901d1c89c9d99005782edPuneet Lall            mAvailability.update(clients == 0);
111e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall            return new SessionImpl(session);
112e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall        }
113e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    }
114e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall
115e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    @Nonnull
116e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    @Override
117e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    public SafeCloseable addCallback(Runnable callback, Executor executor) {
118e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall        return mAvailability.addCallback(callback, executor);
119e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    }
120e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall
121e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    @Nonnull
122e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    @Override
123e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    public Boolean get() {
124e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall        return mAvailability.get();
125e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall    }
126e4e15811211d6470a6182f4a1d080b962caa9ae4Puneet Lall}
127