1/*
2 * Copyright (C) 2011 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
18package android.filterfw;
19
20import android.content.Context;
21import android.filterfw.core.AsyncRunner;
22import android.filterfw.core.FilterGraph;
23import android.filterfw.core.FilterContext;
24import android.filterfw.core.FrameManager;
25import android.filterfw.core.GraphRunner;
26import android.filterfw.core.RoundRobinScheduler;
27import android.filterfw.core.SyncRunner;
28import android.filterfw.io.GraphIOException;
29import android.filterfw.io.GraphReader;
30import android.filterfw.io.TextGraphReader;
31
32import java.util.ArrayList;
33
34/**
35 * A GraphEnvironment provides a simple front-end to filter graph setup and execution using the
36 * mobile filter framework. Typically, you use a GraphEnvironment in the following fashion:
37 *   1. Instantiate a new GraphEnvironment instance.
38 *   2. Perform any configuration, such as adding graph references and setting a GL environment.
39 *   3. Load a graph file using loadGraph() or add a graph using addGraph().
40 *   4. Obtain a GraphRunner instance using getRunner().
41 *   5. Execute the obtained runner.
42 * Note that it is possible to add multiple graphs and runners to a single GraphEnvironment.
43 *
44 * @hide
45 */
46public class GraphEnvironment extends MffEnvironment {
47
48    public static final int MODE_ASYNCHRONOUS = 1;
49    public static final int MODE_SYNCHRONOUS  = 2;
50
51    private GraphReader mGraphReader;
52    private ArrayList<GraphHandle> mGraphs = new ArrayList<GraphHandle>();
53
54    private class GraphHandle {
55        private FilterGraph mGraph;
56        private AsyncRunner mAsyncRunner;
57        private SyncRunner mSyncRunner;
58
59        public GraphHandle(FilterGraph graph) {
60            mGraph = graph;
61        }
62
63        public FilterGraph getGraph() {
64            return mGraph;
65        }
66
67        public AsyncRunner getAsyncRunner(FilterContext environment) {
68            if (mAsyncRunner == null) {
69                mAsyncRunner = new AsyncRunner(environment, RoundRobinScheduler.class);
70                mAsyncRunner.setGraph(mGraph);
71            }
72            return mAsyncRunner;
73        }
74
75        public GraphRunner getSyncRunner(FilterContext environment) {
76            if (mSyncRunner == null) {
77                mSyncRunner = new SyncRunner(environment, mGraph, RoundRobinScheduler.class);
78            }
79            return mSyncRunner;
80        }
81    }
82
83    /**
84     * Create a new GraphEnvironment with default components.
85     */
86    public GraphEnvironment() {
87        super(null);
88    }
89
90    /**
91     * Create a new GraphEnvironment with a custom FrameManager and GraphReader. Specifying null
92     * for either of these, will auto-create a default instance.
93     *
94     * @param frameManager The FrameManager to use, or null to auto-create one.
95     * @param reader        The GraphReader to use for graph loading, or null to auto-create one.
96     *                      Note, that the reader will not be created until it is required. Pass
97     *                      null if you will not load any graph files.
98     */
99    public GraphEnvironment(FrameManager frameManager, GraphReader reader) {
100        super(frameManager);
101        mGraphReader = reader;
102    }
103
104    /**
105     * Returns the used graph reader. This will create one, if a reader has not been set already.
106     */
107    public GraphReader getGraphReader() {
108        if (mGraphReader == null) {
109            mGraphReader = new TextGraphReader();
110        }
111        return mGraphReader;
112    }
113
114    /**
115     * Add graph references to resolve during graph reading. The references added here are shared
116     * among all graphs.
117     *
118     * @param references An alternating argument list of keys (Strings) and values.
119     */
120    public void addReferences(Object... references) {
121        getGraphReader().addReferencesByKeysAndValues(references);
122    }
123
124    /**
125     * Loads a graph file from the specified resource and adds it to this environment.
126     *
127     * @param context       The context in which to read the resource.
128     * @param resourceId    The ID of the graph resource to load.
129     * @return              A unique ID for the graph.
130     */
131    public int loadGraph(Context context, int resourceId) {
132        // Read the file into a graph
133        FilterGraph graph = null;
134        try {
135            graph = getGraphReader().readGraphResource(context, resourceId);
136        } catch (GraphIOException e) {
137            throw new RuntimeException("Could not read graph: " + e.getMessage());
138        }
139
140        // Add graph to our list of graphs
141        return addGraph(graph);
142    }
143
144    /**
145     * Add a graph to the environment. Consider using loadGraph() if you are loading a graph from
146     * a graph file.
147     *
148     * @param graph The graph to add to the environment.
149     * @return      A unique ID for the added graph.
150     */
151    public int addGraph(FilterGraph graph) {
152        GraphHandle graphHandle = new GraphHandle(graph);
153        mGraphs.add(graphHandle);
154        return mGraphs.size() - 1;
155    }
156
157    /**
158     * Access a specific graph of this environment given a graph ID (previously returned from
159     * loadGraph() or addGraph()). Throws an InvalidArgumentException if no graph with the
160     * specified ID could be found.
161     *
162     * @param graphId   The ID of the graph to get.
163     * @return          The graph with the specified ID.
164     */
165    public FilterGraph getGraph(int graphId) {
166        if (graphId < 0 || graphId >= mGraphs.size()) {
167            throw new IllegalArgumentException(
168                "Invalid graph ID " + graphId + " specified in runGraph()!");
169        }
170        return mGraphs.get(graphId).getGraph();
171    }
172
173    /**
174     * Get a GraphRunner instance for the graph with the specified ID. The GraphRunner instance can
175     * be used to execute the graph. Throws an InvalidArgumentException if no graph with the
176     * specified ID could be found.
177     *
178     * @param graphId       The ID of the graph to get.
179     * @param executionMode The mode of graph execution. Currently this can be either
180                            MODE_SYNCHRONOUS or MODE_ASYNCHRONOUS.
181     * @return              A GraphRunner instance for this graph.
182     */
183    public GraphRunner getRunner(int graphId, int executionMode) {
184        switch (executionMode) {
185            case MODE_ASYNCHRONOUS:
186                return mGraphs.get(graphId).getAsyncRunner(getContext());
187
188            case MODE_SYNCHRONOUS:
189                return mGraphs.get(graphId).getSyncRunner(getContext());
190
191            default:
192                throw new RuntimeException(
193                    "Invalid execution mode " + executionMode + " specified in getRunner()!");
194        }
195    }
196
197}
198