16 |
--------------------------------------------------------------------------------
/app/build/intermediates/res/merged/debug/values-v11/values-v11.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
--------------------------------------------------------------------------------
/app/build/intermediates/res/merged/debug/values-v14/values-v14.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
--------------------------------------------------------------------------------
/app/build/intermediates/res/merged/debug/values/values.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | Local.247
6 | vchat1
7 | Settings
8 | Licode + Libjingle
9 | Hello world!
10 | FAIL! Not connected to video server.
11 | Connecting video
12 | Videochat OFF
13 | Videochat ON
14 |
21 |
24 |
--------------------------------------------------------------------------------
/app/build/intermediates/res/resources-debug-androidTest.ap_:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonahzheng/licodeClientForAndroid/d1a63f06536c507f127a5f62dcf1b6d4a25a15e4/app/build/intermediates/res/resources-debug-androidTest.ap_
--------------------------------------------------------------------------------
/app/build/intermediates/res/resources-debug.ap_:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonahzheng/licodeClientForAndroid/d1a63f06536c507f127a5f62dcf1b6d4a25a15e4/app/build/intermediates/res/resources-debug.ap_
--------------------------------------------------------------------------------
/app/build/outputs/logs/manifest-merger-debug-report.txt:
--------------------------------------------------------------------------------
1 | -- Merging decision tree log ---
2 | manifest
3 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:2:1-39:12
4 | package
5 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:3:5-39
6 | INJECTED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml
7 | INJECTED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml
8 | android:versionName
9 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:5:5-30
10 | INJECTED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml
11 | INJECTED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml
12 | android:versionCode
13 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:4:5-28
14 | INJECTED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml
15 | INJECTED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml
16 | xmlns:android
17 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:2:11-69
18 | android:installLocation
19 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:6:5-45
20 | uses-sdk
21 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:8:5-10:41
22 | android:targetSdkVersion
23 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:10:9-38
24 | INJECTED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml
25 | INJECTED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml
26 | android:minSdkVersion
27 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:9:9-35
28 | INJECTED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml
29 | INJECTED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml
30 | uses-permission#android.permission.INTERNET
31 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:12:5-67
32 | android:name
33 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:12:22-64
34 | uses-feature#android.hardware.camera
35 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:13:5-60
36 | android:name
37 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:13:19-57
38 | uses-feature#android.hardware.camera.autofocus
39 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:14:5-70
40 | android:name
41 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:14:19-67
42 | uses-permission#android.permission.MODIFY_AUDIO_SETTINGS
43 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:15:5-80
44 | android:name
45 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:15:22-77
46 | uses-permission#android.permission.RECORD_AUDIO
47 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:16:5-71
48 | android:name
49 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:16:22-68
50 | uses-permission#android.permission.WAKE_LOCK
51 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:17:5-68
52 | android:name
53 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:17:22-65
54 | uses-permission#android.permission.WRITE_EXTERNAL_STORAGE
55 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:18:5-80
56 | android:name
57 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:18:22-78
58 | uses-permission#android.permission.CAMERA
59 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:19:5-81
60 | android:name
61 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:19:22-62
62 | application
63 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:21:5-37:19
64 | android:label
65 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:24:9-41
66 | android:allowBackup
67 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:22:9-35
68 | android:icon
69 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:23:9-45
70 | android:theme
71 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:25:9-40
72 | activity#com.example.licodeclient.MainActivity
73 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:26:9-36:20
74 | android:label
75 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:28:13-45
76 | android:configChanges
77 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:29:13-72
78 | android:name
79 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:27:13-65
80 | intent-filter#android.intent.action.MAIN+android.intent.category.LAUNCHER
81 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:31:13-35:29
82 | action#android.intent.action.MAIN
83 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:32:17-69
84 | android:name
85 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:32:25-66
86 | category#android.intent.category.LAUNCHER
87 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:34:17-77
88 | android:name
89 | ADDED from C:\Users\95\AndroidStudioProjects\licodeAndroidClient-master\app\src\main\AndroidManifest.xml:34:27-74
90 |
--------------------------------------------------------------------------------
/app/libs/androidasync-1.2.6.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonahzheng/licodeClientForAndroid/d1a63f06536c507f127a5f62dcf1b6d4a25a15e4/app/libs/androidasync-1.2.6.jar
--------------------------------------------------------------------------------
/app/libs/libjingle_peerconnection.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonahzheng/licodeClientForAndroid/d1a63f06536c507f127a5f62dcf1b6d4a25a15e4/app/libs/libjingle_peerconnection.jar
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
26 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/licodeclient/FragmentVideoChat.java:
--------------------------------------------------------------------------------
1 | package com.example.licodeclient;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.io.OutputStream;
6 | import java.net.HttpURLConnection;
7 | import java.net.MalformedURLException;
8 | import java.net.URL;
9 | import java.util.Map;
10 | import java.util.concurrent.ConcurrentHashMap;
11 |
12 | import android.app.Fragment;
13 | import android.content.res.Configuration;
14 | import android.graphics.Point;
15 | import android.os.AsyncTask;
16 | import android.os.Build;
17 | import android.os.Bundle;
18 | import android.view.Gravity;
19 | import android.view.LayoutInflater;
20 | import android.view.Menu;
21 | import android.view.MenuInflater;
22 | import android.view.MenuItem;
23 | import android.view.View;
24 | import android.view.ViewGroup;
25 | import android.widget.ImageView;
26 | import android.widget.Toast;
27 |
28 | import com.example.licodeclient.StreamDescriptionInterface.StreamState;
29 | import com.example.licodeclient.apprtc.VideoStreamsView;
30 |
31 | /**
32 | * simple fragment to display two rows of video streams
33 | */
34 | public class FragmentVideoChat extends Fragment {
35 | // TODO replace this with your servers url!
36 | /** server url - where to request tokens */
37 | private String mTokenServerUrl = "http://192.168.0.42:3001";
38 |
39 | /** the licode signaling engine */
40 | VideoConnectorInterface mConnector = null;
41 | /** basic size of a video stream */
42 | Point mBasicViewSize = null;
43 | /** the container for all the videos */
44 | VideoGridLayout mContainer = null;
45 | /** the video streams view */
46 | VideoStreamsView mVsv = null;
47 | /** map of stream id -> video view */
48 | ConcurrentHashMap mVideoViews = new ConcurrentHashMap();
49 |
50 | /**
51 | * click listener for the video views - will typically change the view from
52 | * normal to zoomed mode
53 | */
54 | private View.OnClickListener mVsvClickListener = new View.OnClickListener() {
55 | @Override
56 | public void onClick(View v) {
57 | if (mContainer != null) {
58 | String streamId = ((VideoStreamPlaceholder) v).getStreamId();
59 | StreamDescriptionInterface stream = mConnector
60 | .getRemoteStreams().get(streamId);
61 | if (stream != null) {
62 | stream.setAudioActive(!stream.isAudioActive());
63 | }
64 | }
65 | }
66 | };
67 |
68 | /** the room observer instance for this fragment */
69 | private VideoConnectorInterface.RoomObserver mRoomObserver;
70 | /** the view to start casting video stream */
71 | private ImageView mStartCastView;
72 |
73 | /**
74 | * create or retrieve a display element for given stream - will add this to
75 | * the appropriate list and the container element for video streams.
76 | *
77 | * @param stream
78 | * The source of the video data.
79 | * @return An existing video display element, or a newly created one.
80 | */
81 | protected VideoStreamPlaceholder makeVideoView(String streamId) {
82 | mVsv.addStream(streamId);
83 | if (mVideoViews.containsKey(streamId)) {
84 | return mVideoViews.get(streamId);
85 | } else if (getActivity() != null) {
86 | VideoStreamPlaceholder vsp = new VideoStreamPlaceholder(
87 | getActivity(), mVsv, streamId);
88 | vsp.setOnClickListener(mVsvClickListener);
89 |
90 | mVideoViews.put(streamId, vsp);
91 | mContainer.addView(vsp);
92 | return vsp;
93 | }
94 |
95 | // no activity? this is a dead fragment
96 | return null;
97 | }
98 |
99 | @Override
100 | public void onCreate(Bundle savedInstanceState) {
101 | super.onCreate(savedInstanceState);
102 | }
103 |
104 | /** helper function - called to prepare the video chat connector instance */
105 | private void configureConnector() {
106 | mConnector = new LicodeConnector();
107 | mConnector.init(getActivity(), "user");
108 |
109 | mRoomObserver = new VideoConnectorInterface.RoomObserver() {
110 | @Override
111 | public void onStreamRemoved(final StreamDescriptionInterface stream) {
112 | if (stream == null || getActivity() == null
113 | || mContainer == null) {
114 | return;
115 | }
116 |
117 | getActivity().runOnUiThread(new Runnable() {
118 |
119 | @Override
120 | public void run() {
121 | String streamId = stream.isLocal() ? VideoStreamsView.LOCAL_STREAM_ID
122 | : stream.getId();
123 | VideoStreamPlaceholder vsp = mVideoViews.get(streamId);
124 | if (vsp != null) {
125 | mVideoViews.remove(streamId);
126 | mContainer.removeView(vsp);
127 | }
128 | stream.detachRenderer();
129 | mVsv.removeStream(streamId);
130 | mConnector.destroy(stream);
131 |
132 | if (stream.isLocal()) {
133 | mStartCastView.setVisibility(mConnector
134 | .isPublishing() ? View.GONE : View.VISIBLE);
135 | }
136 | }
137 | });
138 | }
139 |
140 | @Override
141 | public void onStreamData(String message,
142 | StreamDescriptionInterface stream) {
143 | // ignored, for now
144 | }
145 |
146 | @Override
147 | public void onStreamAdded(final StreamDescriptionInterface stream) {
148 | if (getActivity() == null) {
149 | return;
150 | }
151 | getActivity().runOnUiThread(new Runnable() {
152 |
153 | @Override
154 | public void run() {
155 | mConnector.subscribe(stream);
156 | }
157 | });
158 | }
159 |
160 | @Override
161 | public void onRoomDisconnected() {
162 | if (getActivity() == null) {
163 | return;
164 | }
165 | getActivity().runOnUiThread(new Runnable() {
166 | @Override
167 | public void run() {
168 | for (String key : mVideoViews.keySet()) {
169 | VideoStreamPlaceholder vsp = mVideoViews.get(key);
170 | if (vsp != null) {
171 | mContainer.removeView(vsp);
172 | }
173 | mVsv.removeStream(key);
174 | }
175 | mVideoViews.clear();
176 | mVsv.onPause();
177 |
178 | if (getActivity() != null) {
179 | getActivity().invalidateOptionsMenu();
180 | }
181 | }
182 | });
183 | }
184 |
185 | @Override
186 | public void onRoomConnected(
187 | Map streamList) {
188 | mConnector.setBandwidthLimits(84, 16);
189 |
190 | if (getActivity() == null) {
191 | return;
192 | }
193 |
194 | // getActivity().supportInvalidateOptionsMenu();
195 |
196 | getActivity().runOnUiThread(new Runnable() {
197 |
198 | @Override
199 | public void run() {
200 | // TODO: Disconnect enable?
201 | if (getActivity() != null) {
202 | getActivity().invalidateOptionsMenu();
203 | }
204 | }
205 | });
206 | }
207 |
208 | @Override
209 | public void onStreamMediaAvailable(
210 | final StreamDescriptionInterface stream) {
211 | if (mContainer == null) {
212 | return;
213 | }
214 | mContainer.post(new Runnable() {
215 | @Override
216 | public void run() {
217 | if (mContainer == null) {
218 | return;
219 | }
220 | makeVideoView(stream.getId());
221 | mConnector.attachRenderer(stream, mVsv);
222 | }
223 | });
224 | }
225 |
226 | @Override
227 | public void onPublishAllowed() {
228 | startPublish();
229 | }
230 |
231 | @Override
232 | public void onRequestRefreshToken() {
233 | startRefreshToken();
234 | }
235 | };
236 | mConnector.addObserver(mRoomObserver);
237 | }
238 |
239 | @Override
240 | public void onStart() {
241 | super.onStart();
242 |
243 | if (mConnector != null && mConnector.isConnected()
244 | && mContainer != null) {
245 | mContainer.setCollapsed(false);
246 | mContainer.post(new Runnable() {
247 |
248 | @Override
249 | public void run() {
250 | if (getView() == null || getActivity() == null) {
251 | return;
252 | }
253 | Map streams = mConnector
254 | .getRemoteStreams();
255 | for (String key : streams.keySet()) {
256 | StreamDescriptionInterface stream = streams.get(key);
257 | if (stream != null
258 | && stream.getState() != StreamState.CLOSING) {
259 | mConnector.subscribe(stream);
260 | }
261 | }
262 |
263 | if (mConnector.isPublishing()) {
264 | makeVideoView(VideoStreamsView.LOCAL_STREAM_ID);
265 | mConnector.attachLocalStream(mVsv);
266 | }
267 | }
268 | });
269 | }
270 | }
271 |
272 | @Override
273 | public void onStop() {
274 | super.onStop();
275 |
276 | if (mConnector != null) {
277 | Map streams = mConnector
278 | .getRemoteStreams();
279 | for (String key : mVideoViews.keySet()) {
280 | StreamDescriptionInterface stream = streams.get(key);
281 | if (stream != null) {
282 | stream.detachRenderer();
283 | }
284 | }
285 |
286 | mConnector.detachLocalStream();
287 |
288 | // TODO dk: check if detaching is necessary if we cut connection
289 | // entirely?
290 | mConnector.disconnect();
291 | }
292 | }
293 |
294 | @Override
295 | public void onPause() {
296 | super.onPause();
297 |
298 | mVsv.onPause();
299 | // mConnector.onPause();
300 | }
301 |
302 | @Override
303 | public void onResume() {
304 | super.onResume();
305 |
306 | mVsv.onResume();
307 | // mConnector.onResume();
308 | }
309 |
310 | @Override
311 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
312 | Bundle savedInstanceState) {
313 | configureConnector();
314 | setHasOptionsMenu(true);
315 |
316 | View mainView = inflater.inflate(R.layout.fragment_videochat,
317 | container, false);
318 |
319 | mContainer = (VideoGridLayout) mainView
320 | .findViewById(R.id.videochat_grid);
321 | mContainer.setCollapsed(false);
322 |
323 | if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
324 | mContainer.setGridDimensions(9, 1);
325 | } else {
326 | mContainer.setGridDimensions(3, 3);
327 | }
328 |
329 | mVsv = new VideoStreamsView(this.getActivity());
330 | mContainer.addView(mVsv);
331 | mContainer.setVideoElement(mVsv);
332 |
333 | final ImageView startCastView = new ImageView(getActivity());
334 | mStartCastView = startCastView;
335 | startCastView.setImageResource(R.drawable.streamself);
336 | startCastView.setOnClickListener(new View.OnClickListener() {
337 | @Override
338 | public void onClick(final View v) {
339 | if (mConnector == null || !mConnector.isConnected()) {
340 | Toast.makeText(getActivity(),
341 | R.string.videochatFailNotConnected,
342 | Toast.LENGTH_LONG).show();
343 | return;
344 | }
345 | v.postDelayed(new Runnable() {
346 | public void run() {
347 | if (mConnector != null && mConnector.isConnected()) {
348 | mConnector.requestPublish();
349 | }
350 | }
351 | }, 100L); // TODO dk: hardcoded delay!
352 | Toast toast = Toast.makeText(getActivity(),
353 | R.string.videochatWaitConnecting, Toast.LENGTH_SHORT);
354 | toast.setGravity(Gravity.CENTER, 0, 0);
355 | toast.show();
356 | }
357 | });
358 | mContainer.addView(startCastView);
359 | startCastView.setVisibility(mConnector.isPublishing() ? View.GONE
360 | : View.VISIBLE);
361 | startCastView.setLayoutParams(new VideoGridLayout.LayoutParams(
362 | Integer.MAX_VALUE));
363 |
364 | return mainView;
365 | }
366 |
367 | @Override
368 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
369 | inflater.inflate(R.menu.main, menu);
370 |
371 | boolean connected = false;
372 | if (mConnector != null) {
373 | connected = mConnector.isConnected();
374 | }
375 |
376 | menu.findItem(R.id.action_vchat_connect).setVisible(!connected);
377 | menu.findItem(R.id.action_vchat_disconnect).setVisible(connected);
378 | }
379 |
380 | @Override
381 | public boolean onOptionsItemSelected(MenuItem item) {
382 | int id = item.getItemId();
383 | switch (id) {
384 | case R.id.action_vchat_connect:
385 | startVideoChat();
386 | break;
387 | case R.id.action_vchat_disconnect:
388 | mConnector.disconnect();
389 | mContainer.setCollapsed(true);
390 | break;
391 | }
392 |
393 | return super.onOptionsItemSelected(item);
394 | }
395 |
396 | /** instantiate a new fragment */
397 | public static FragmentVideoChat createInstance(Bundle extras) {
398 | FragmentVideoChat result = new FragmentVideoChat();
399 | result.setArguments(extras);
400 | return result;
401 | }
402 |
403 | @Override
404 | public void onDestroy() {
405 | super.onDestroy();
406 |
407 | if (mConnector != null) {
408 | mConnector.removeObserver(mRoomObserver);
409 | }
410 | }
411 |
412 | /** publish */
413 | protected void startPublish() {
414 | getActivity().runOnUiThread(new Runnable() {
415 | @Override
416 | public void run() {
417 | if (mConnector != null && mConnector.isConnected()) {
418 | if (mContainer != null) {
419 | /* VideoStreamPlaceholder placeholder = */makeVideoView(VideoStreamsView.LOCAL_STREAM_ID);
420 | }
421 |
422 | mStartCastView.setVisibility(View.GONE);
423 |
424 | mConnector.publish(mVsv);
425 | }
426 | }
427 | });
428 | }
429 |
430 | /** request a new token - to initialize first connection */
431 | private void startVideoChat() {
432 | // begin connection process
433 | FutureResult response = new FutureResult();
434 | response.addResultObserver(new FutureResult.OnResultCallback() {
435 | @Override
436 | public void OnResult(String result) {
437 | mConnector.connect(result);
438 | }
439 | });
440 | new XmlHttpRequest(response).execute(mTokenServerUrl);
441 | }
442 |
443 | /** request a new token - to keep connected */
444 | private void startRefreshToken() {
445 | FutureResult response = new FutureResult();
446 | response.addResultObserver(new FutureResult.OnResultCallback() {
447 | @Override
448 | public void OnResult(String result) {
449 | mConnector.refreshVideoToken(result);
450 | }
451 | });
452 | new XmlHttpRequest(response).execute(mTokenServerUrl);
453 | }
454 |
455 | /** helper class - fake xml http request */
456 | private static class XmlHttpRequest extends AsyncTask {
457 | FutureResult mResponse;
458 |
459 | public XmlHttpRequest(FutureResult futureResponse) {
460 | mResponse = futureResponse;
461 | }
462 |
463 | @Override
464 | protected String doInBackground(String... params) {
465 | String response = null;
466 | HttpURLConnection conn = null;
467 | InputStream is = null;
468 | OutputStream os = null;
469 | try {
470 | URL url = new URL(params[0] + "/createToken/");
471 | String message = "{";
472 | message += "\"username\": \"user\", ";
473 | message += "\"role\": \"presenter\" ";
474 | message += " }";
475 | conn = (HttpURLConnection) url.openConnection();
476 | conn.setRequestMethod("POST");
477 | conn.setDoInput(true);
478 | conn.setDoOutput(true);
479 | conn.setFixedLengthStreamingMode(message.getBytes().length);
480 |
481 | if (Build.VERSION.SDK_INT > 13) {
482 | conn.setRequestProperty("Connection", "close");
483 | }
484 |
485 | conn.setRequestProperty("Content-Type",
486 | "application/json;charset=utf-8");
487 | conn.setRequestProperty("X-Request-With", "XMLHttpRequest");
488 |
489 | conn.connect();
490 |
491 | os = conn.getOutputStream();
492 | os.write(message.getBytes());
493 | os.flush();
494 |
495 | is = conn.getInputStream();
496 | StringBuffer sb = new StringBuffer();
497 | int ch = -1;
498 | while ((ch = is.read()) != -1) {
499 | sb.append((char) ch);
500 | }
501 | response = sb.toString();
502 |
503 | if (os != null) {
504 | os.close();
505 | }
506 | if (is != null) {
507 | is.close();
508 | }
509 | } catch (MalformedURLException e) {
510 | e.printStackTrace();
511 | } catch (IOException e) {
512 | e.printStackTrace();
513 | } finally {
514 | if (conn != null) {
515 | conn.disconnect();
516 | }
517 | }
518 | return response;
519 | }
520 |
521 | @Override
522 | protected void onPostExecute(String result) {
523 | if (mResponse != null) {
524 | mResponse.setResult(result);
525 | mResponse = null;
526 | }
527 | }
528 | }
529 |
530 | }
531 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/licodeclient/FutureResult.java:
--------------------------------------------------------------------------------
1 | package com.example.licodeclient;
2 |
3 | import java.util.concurrent.ConcurrentLinkedQueue;
4 | import java.util.concurrent.ExecutionException;
5 | import java.util.concurrent.Future;
6 | import java.util.concurrent.TimeUnit;
7 | import java.util.concurrent.TimeoutException;
8 |
9 | /**
10 | * Class to hold a future result of a calculation.
11 | *
12 | * Result can be set by setResult.
13 | *
14 | * @param
15 | */
16 | public class FutureResult implements Future {
17 | public interface OnResultCallback {
18 | void OnResult(V result);
19 | }
20 |
21 | /** the result - once it has been set */
22 | private volatile V mResult = null;
23 | /** set when cancelled or done */
24 | private volatile boolean mDone = false;
25 | /** all observers who want to know about the result reached event */
26 | private ConcurrentLinkedQueue> mObservers = new ConcurrentLinkedQueue>();
27 |
28 | @Override
29 | public boolean cancel(boolean mayInterruptIfRunning) {
30 | mDone = true;
31 | return false;
32 | }
33 |
34 | @Override
35 | public V get() throws InterruptedException, ExecutionException {
36 | while (mDone == false) {
37 | Thread.sleep(100);
38 | }
39 | return mResult;
40 | }
41 |
42 | @Override
43 | public V get(long timeout, TimeUnit unit) throws InterruptedException,
44 | ExecutionException, TimeoutException {
45 |
46 | long remainingTime = TimeUnit.MILLISECONDS.convert(timeout, unit);
47 | while (mDone == false && remainingTime > 0) {
48 | long t = 100L;
49 | remainingTime -= t;
50 | Thread.sleep(t);
51 | }
52 | return mResult;
53 | }
54 |
55 | @Override
56 | public boolean isCancelled() {
57 | return false;
58 | }
59 |
60 | @Override
61 | public boolean isDone() {
62 | return mDone;
63 | }
64 |
65 | /** set the result and as such turn this future real */
66 | public void setResult(V result) {
67 | mResult = result;
68 | mDone = true;
69 |
70 | for (OnResultCallback callback : mObservers) {
71 | callback.OnResult(result);
72 | }
73 | }
74 |
75 | /** attach a result observer */
76 | public void addResultObserver(OnResultCallback observer) {
77 | mObservers.add(observer);
78 | }
79 |
80 | /** remove a result observer from this future */
81 | public void removeResultObserver(OnResultCallback observer) {
82 | mObservers.remove(observer);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/licodeclient/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.licodeclient;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 |
6 | public class MainActivity extends Activity {
7 |
8 | @Override
9 | protected void onCreate(Bundle savedInstanceState) {
10 | super.onCreate(savedInstanceState);
11 | this.setContentView(R.layout.activity_main);
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/licodeclient/StreamDescription.java:
--------------------------------------------------------------------------------
1 | package com.example.licodeclient;
2 |
3 | import org.json.JSONException;
4 | import org.json.JSONObject;
5 | import org.webrtc.MediaConstraints;
6 | import org.webrtc.MediaStream;
7 | import org.webrtc.PeerConnection;
8 | import org.webrtc.SdpObserver;
9 | import org.webrtc.VideoRenderer;
10 |
11 | public class StreamDescription implements StreamDescriptionInterface {
12 | /** current state of the stream */
13 | private StreamState mState = StreamState.UNKNOWN;
14 |
15 | /** identifier for this stream */
16 | private String mId;
17 |
18 | /** has data? */
19 | private boolean mData;
20 | /** has video? */
21 | private boolean mVideo;
22 | /** has screen stream? */
23 | private boolean mScreen;
24 | /** has audio? */
25 | private boolean mAudio;
26 |
27 | /** the attribute information */
28 | private JSONObject mAttributes = new JSONObject();
29 |
30 | /** the nick attached to this stream - if any */
31 | private String mNick;
32 |
33 | /**
34 | * flag to store if stream is outgoing (true, local) or incoming (false,
35 | * remote)
36 | */
37 | private boolean mLocal;
38 |
39 | /** sdp constraints for the sdp */
40 | private MediaConstraints mSdpConstraints;
41 |
42 | /** flag - stores if audio is currently allowed to play, or not */
43 | private boolean mAudioActive = true;
44 |
45 | public static StreamDescription parseJson(JSONObject arg) {
46 | String id = null;
47 | boolean data = false;
48 | boolean video = false;
49 | boolean audio = false;
50 | boolean screen = false;
51 | JSONObject attr = null;
52 | String nick = null;
53 |
54 | try {
55 | id = arg.getString("id");
56 | } catch (JSONException e) {
57 | }
58 | try {
59 | data = arg.getBoolean("data");
60 | } catch (JSONException e3) {
61 | }
62 | try {
63 | video = arg.getBoolean("video");
64 | } catch (JSONException e2) {
65 | }
66 | try {
67 | audio = arg.getBoolean("audio");
68 | } catch (JSONException e1) {
69 | }
70 | try {
71 | screen = arg.getBoolean("screen");
72 | } catch (JSONException e) {
73 | }
74 | try {
75 | attr = arg.getJSONObject("attributes");
76 | if (attr != null) {
77 | nick = attr.getString("nick");
78 | }
79 | } catch (JSONException e) {
80 | }
81 |
82 | return new StreamDescription(id, data, video, audio, screen, attr, nick);
83 | }
84 |
85 | public StreamDescription(String id, boolean data, boolean video,
86 | boolean audio, boolean screen, JSONObject attr, String nick) {
87 | mId = id;
88 | mData = data;
89 | mVideo = video;
90 | mAudio = audio;
91 | mScreen = screen;
92 | if (attr != null) {
93 | mAttributes = attr;
94 | }
95 | mNick = nick;
96 | }
97 |
98 | /*
99 | * (non-Javadoc)
100 | *
101 | * @see
102 | * com.knuddels.android.activities.webrtc.StreamDescriptionInteface#toJson()
103 | */
104 | @Override
105 | public JSONObject toJson() {
106 | JSONObject result = new JSONObject();
107 | try {
108 | result.put("data", mData);
109 | result.put("video", mVideo);
110 | result.put("audio", mAudio);
111 | result.put("screen", mScreen);
112 | if (mAttributes == null) {
113 | mAttributes = new JSONObject();
114 | }
115 | mAttributes.put("nick", mNick);
116 | result.put("attributes", mAttributes);
117 | } catch (JSONException e) {
118 | // TODO Auto-generated catch block
119 | e.printStackTrace();
120 | }
121 |
122 | return result;
123 | }
124 |
125 | /*
126 | * (non-Javadoc)
127 | *
128 | * @see
129 | * com.knuddels.android.activities.webrtc.StreamDescriptionInteface#getId()
130 | */
131 | @Override
132 | public String getId() {
133 | return mId;
134 | }
135 |
136 | /*
137 | * (non-Javadoc)
138 | *
139 | * @see
140 | * com.knuddels.android.activities.webrtc.StreamDescriptionInteface#setId
141 | * (java.lang.String)
142 | */
143 | @Override
144 | public void setId(String newId) {
145 | if (mLocal) {
146 | mId = newId;
147 | } else {
148 | throw new UnsupportedOperationException(
149 | "May not change id of a non-local stream!");
150 | }
151 | }
152 |
153 | /*
154 | * (non-Javadoc)
155 | *
156 | * @see
157 | * com.knuddels.android.activities.webrtc.StreamDescriptionInteface#isLocal
158 | * ()
159 | */
160 | @Override
161 | public boolean isLocal() {
162 | return mLocal;
163 | }
164 |
165 | /*
166 | * (non-Javadoc)
167 | *
168 | * @see
169 | * com.knuddels.android.activities.webrtc.StreamDescriptionInteface#toJsonOffer
170 | * (java.lang.String)
171 | */
172 | @Override
173 | public JSONObject toJsonOffer(String state) {
174 | JSONObject result = new JSONObject();
175 | try {
176 | if (state != null) {
177 | result.put("state", state);
178 | }
179 | result.put("data", mData);
180 | result.put("audio", mAudio);
181 | result.put("video", mVideo);
182 | if (mAttributes == null) {
183 | mAttributes = new JSONObject();
184 | }
185 | mAttributes.put("nick", mNick);
186 | result.put("attributes", mAttributes);
187 | } catch (JSONException jex) {
188 | // TODO
189 | jex.printStackTrace();
190 | }
191 |
192 | return result;
193 | }
194 |
195 | public PeerConnection pc = null;
196 | /** the active media stream */
197 | private volatile MediaStream mMediaStream;
198 | /** currently set video renderer */
199 | private VideoRenderer mRenderer;
200 |
201 | /** access the sdp's constraints */
202 | public MediaConstraints sdpConstraints() {
203 | return mSdpConstraints;
204 | }
205 |
206 | public void initLocal(PeerConnection pc, SdpObserver sdpObserver) {
207 | mLocal = true;
208 | mState = StreamState.LOCAL;
209 | this.pc = pc;
210 | mSdpConstraints = new MediaConstraints();
211 | mSdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair(
212 | "OfferToReceiveAudio", "true"));
213 | mSdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair(
214 | "OfferToReceiveVideo", "true"));
215 | pc.createOffer(sdpObserver, mSdpConstraints);
216 | }
217 |
218 | public void initRemote(PeerConnection pc, SdpObserver sdpObserver) {
219 | mLocal = false;
220 | mState = StreamState.OPENING;
221 | this.pc = pc;
222 | mSdpConstraints = new MediaConstraints();
223 | mSdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair(
224 | "OfferToReceiveAudio", "true"));
225 | mSdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair(
226 | "OfferToReceiveVideo", "true"));
227 | pc.createOffer(sdpObserver, mSdpConstraints);
228 | }
229 |
230 | /** sets the associated media stream - if prepared */
231 | public void setMedia(MediaStream media) {
232 | mMediaStream = media;
233 | }
234 |
235 | /** access the media stream - may be null */
236 | public MediaStream getMedia() {
237 | return mMediaStream;
238 | }
239 |
240 | /** attach a renderer to the media */
241 | public synchronized void attachRenderer(
242 | LicodeConnector.VideoCallbacks videoCallbacks) {
243 | if (mRenderer != null) {
244 | return;
245 | }
246 | if (mMediaStream != null && mMediaStream.videoTracks.size() == 1) {
247 | mState = StreamState.ACTIVE;
248 | mRenderer = new VideoRenderer(videoCallbacks);
249 | mMediaStream.videoTracks.get(0).addRenderer(mRenderer);
250 | }
251 | }
252 |
253 | /** attaches a complete renderer */
254 | public synchronized void attachLocalRenderer(VideoRenderer renderer) {
255 | if (mRenderer != null) {
256 | return;
257 | }
258 |
259 | mRenderer = renderer;
260 | }
261 |
262 | /*
263 | * (non-Javadoc)
264 | *
265 | * @see com.knuddels.android.activities.webrtc.StreamDescriptionInteface#
266 | * detachRenderer()
267 | */
268 | @Override
269 | public synchronized void detachRenderer() {
270 | if (mRenderer != null && mMediaStream != null
271 | && mMediaStream.videoTracks.size() == 1) {
272 | mMediaStream.videoTracks.get(0).removeRenderer(mRenderer);
273 | }
274 | mRenderer = null;
275 | }
276 |
277 | /*
278 | * (non-Javadoc)
279 | *
280 | * @see
281 | * com.knuddels.android.activities.webrtc.StreamDescriptionInteface#onClosing
282 | * ()
283 | */
284 | @Override
285 | public void onClosing() {
286 | mState = StreamState.CLOSING;
287 | }
288 |
289 | /*
290 | * (non-Javadoc)
291 | *
292 | * @see
293 | * com.knuddels.android.activities.webrtc.StreamDescriptionInteface#onDestroyed
294 | * ()
295 | */
296 | @Override
297 | public void onDestroyed() {
298 | mState = StreamState.DESTROYED;
299 | mMediaStream = null;
300 | }
301 |
302 | /*
303 | * (non-Javadoc)
304 | *
305 | * @see
306 | * com.knuddels.android.activities.webrtc.StreamDescriptionInteface#onDisable
307 | * ()
308 | */
309 | @Override
310 | public void onDisable() {
311 | mState = StreamState.BLOCKED;
312 | mMediaStream = null;
313 | }
314 |
315 | /*
316 | * (non-Javadoc)
317 | *
318 | * @see
319 | * com.knuddels.android.activities.webrtc.StreamDescriptionInteface#getState
320 | * ()
321 | */
322 | @Override
323 | public StreamState getState() {
324 | return mState;
325 | }
326 |
327 | /*
328 | * (non-Javadoc)
329 | *
330 | * @see
331 | * com.knuddels.android.activities.webrtc.StreamDescriptionInteface#toggleAudio
332 | * ()
333 | */
334 | @Override
335 | public void toggleAudio() {
336 | setAudioActive(!mAudioActive);
337 | }
338 |
339 | /*
340 | * (non-Javadoc)
341 | *
342 | * @see com.knuddels.android.activities.webrtc.StreamDescriptionInteface#
343 | * setAudioActive(boolean)
344 | */
345 | @Override
346 | public void setAudioActive(boolean audioActive) {
347 | mAudioActive = audioActive;
348 | if (mMediaStream != null && mMediaStream.audioTracks.size() == 1) {
349 | mMediaStream.audioTracks.get(0).setEnabled(mAudioActive);
350 | }
351 | }
352 |
353 | /*
354 | * (non-Javadoc)
355 | *
356 | * @see com.knuddels.android.activities.webrtc.StreamDescriptionInteface#
357 | * isAudioActive()
358 | */
359 | @Override
360 | public boolean isAudioActive() {
361 | return mAudioActive;
362 | }
363 |
364 | @Override
365 | public String getNick() {
366 | if (mNick != null) {
367 | return mNick;
368 | }
369 | if (mAttributes != null) {
370 | try {
371 | return mAttributes.getString("nick");
372 | } catch (JSONException e) {
373 | }
374 | }
375 | return null;
376 | }
377 |
378 | /** check if this stream has been abandoned by the video server */
379 | public boolean isClosing() {
380 | return mState == StreamState.CLOSING;
381 | }
382 |
383 | }
384 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/licodeclient/StreamDescriptionInterface.java:
--------------------------------------------------------------------------------
1 | package com.example.licodeclient;
2 |
3 | import org.json.JSONObject;
4 |
5 | public interface StreamDescriptionInterface {
6 |
7 | /** stream states - mostly remote stuff, or local */
8 | public enum StreamState {
9 | UNKNOWN, OPENING, ACTIVE, CLOSING, DESTROYED, LOCAL, BLOCKED,
10 | }
11 |
12 | public abstract JSONObject toJson();
13 |
14 | /** access this streams unique id */
15 | public abstract String getId();
16 |
17 | /** new id */
18 | public abstract void setId(String newId);
19 |
20 | /** check if this is outgoing (local, true), or incoming (remote, false) */
21 | public abstract boolean isLocal();
22 |
23 | /** generate an offer json object - with given state value */
24 | public abstract JSONObject toJsonOffer(String state);
25 |
26 | /** detach a previously attached renderer */
27 | public abstract void detachRenderer();
28 |
29 | /** server signaled end of stream - should no longer be interesting */
30 | public abstract void onClosing();
31 |
32 | /** local controller instance removed this stream - MUST NOT be used anymore */
33 | public abstract void onDestroyed();
34 |
35 | /** disable/block a stream, can later be subscribed again */
36 | public abstract void onDisable();
37 |
38 | /** retrieve current state of this stream */
39 | public abstract StreamState getState();
40 |
41 | /** toggles audio between active and mute */
42 | public abstract void toggleAudio();
43 |
44 | /** sets the audio allowed state - audio plays, or audio is muted */
45 | public abstract void setAudioActive(boolean audioActive);
46 |
47 | /** checks if audio for this stream is currently playing, or muted */
48 | public abstract boolean isAudioActive();
49 |
50 | /** retrieve the nick associated with this stream - may return null */
51 | public abstract String getNick();
52 |
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/licodeclient/VideoConnectorInterface.java:
--------------------------------------------------------------------------------
1 | package com.example.licodeclient;
2 |
3 | import java.util.Map;
4 |
5 | import android.app.Activity;
6 |
7 | import com.example.licodeclient.apprtc.VideoStreamsView;
8 |
9 | public interface VideoConnectorInterface {
10 |
11 | /** provides callbacks for specific events that can occur in a room */
12 | public interface RoomObserver {
13 | /** connected to room - with the given streams already in the room */
14 | void onRoomConnected(Map streamList);
15 |
16 | /** connection to room lost */
17 | void onRoomDisconnected();
18 |
19 | /**
20 | * signals that a publish slot is now reserved and available for this
21 | * user
22 | */
23 | void onPublishAllowed();
24 |
25 | /** signals that the given stream was added to the room */
26 | void onStreamAdded(StreamDescriptionInterface stream);
27 |
28 | /**
29 | * signals that the given stream now has media available to display -
30 | * after subscribe request!
31 | */
32 | void onStreamMediaAvailable(StreamDescriptionInterface stream);
33 |
34 | /**
35 | * signals that the given stream has just been removed from the room,
36 | * MUST call destroy(stream)
37 | */
38 | void onStreamRemoved(StreamDescriptionInterface stream);
39 |
40 | /** some data received on given stream */
41 | void onStreamData(String message, StreamDescriptionInterface stream);
42 |
43 | /**
44 | * signal that the current token is about to expire - a new one needs to
45 | * be sent
46 | */
47 | void onRequestRefreshToken();
48 | }
49 |
50 | /** various states of the connection to the server */
51 | public enum State {
52 | kUninitialized, kDisconnected, kConnecting, kConnectingWaitingForToken, kConnected, kDisconnecting
53 | }
54 |
55 | public abstract void onPause();
56 |
57 | public abstract void onResume();
58 |
59 | /** retrieve current state */
60 | public abstract State getState();
61 |
62 | /** check if currently connected, or connecting */
63 | public abstract boolean isConnected();
64 |
65 | /** initializes basic stuff */
66 | public abstract void init(Activity context, String nick);
67 |
68 | /** sets the bandwidth limits for video and audio transport */
69 | public abstract void setBandwidthLimits(int video, int audio);
70 |
71 | /** connect with the given token */
72 | public abstract void connect(String token);
73 |
74 | /** send a new token, refreshing an old one, or changing roles */
75 | public abstract void refreshVideoToken(String token);
76 |
77 | /** tells the connector to severe connection */
78 | public abstract void disconnect();
79 |
80 | /** stop receiving a particular stream */
81 | public abstract void unsubscribe(String streamId);
82 |
83 | /** new observer */
84 | public abstract void addObserver(RoomObserver observer);
85 |
86 | /** observer gone */
87 | public abstract void removeObserver(RoomObserver observer);
88 |
89 | /**
90 | * requests the right to publish a video @return true if allowed, will then
91 | * request publish on the callback
92 | */
93 | public abstract boolean requestPublish();
94 |
95 | /** begin streaming to the server - MUST run on UiThread */
96 | public abstract void publish(VideoStreamsView view);
97 |
98 | /** stop a stream from being sent to the server */
99 | public abstract void unpublish();
100 |
101 | /** requests to receive the given stream */
102 | public abstract void subscribe(StreamDescriptionInterface stream);
103 |
104 | /** remove the last bits and pieces of a stream */
105 | public abstract void destroy(StreamDescriptionInterface stream);
106 |
107 | /**
108 | * prevent a stream from being received for now - it's still available for
109 | * later reconnecting
110 | */
111 | public abstract void disable(StreamDescriptionInterface stream);
112 |
113 | /** (un)pause audio from streaming for the moment */
114 | public abstract void setAudioEnabled(boolean enabled);
115 |
116 | /** resets the activity - allows freeing up a previously held instance */
117 | public abstract void setActivity(Activity activity);
118 |
119 | /** access the remote stream list */
120 | public abstract Map getRemoteStreams();
121 |
122 | /**
123 | * check if currently a publishing stream is running, the user is
124 | * broadcasting
125 | */
126 | public abstract boolean isPublishing();
127 |
128 | public abstract void attachLocalStream(VideoStreamsView vsv);
129 |
130 | public abstract void detachLocalStream();
131 |
132 | /** run something on the vc thread */
133 | public abstract void post(Runnable r);
134 |
135 | /**
136 | * attaches a default renderer to the stream, which associates it with the
137 | * given view
138 | */
139 | public abstract void attachRenderer(StreamDescriptionInterface stream,
140 | VideoStreamsView mVsv);
141 |
142 | /** set the current active nick */
143 | public abstract void setNick(String nickname);
144 |
145 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/licodeclient/VideoGridLayout.java:
--------------------------------------------------------------------------------
1 | package com.example.licodeclient;
2 |
3 | import java.util.ArrayList;
4 | import java.util.concurrent.atomic.AtomicInteger;
5 |
6 | import android.annotation.TargetApi;
7 | import android.content.Context;
8 | import android.graphics.Point;
9 | import android.os.Build;
10 | import android.util.AttributeSet;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 |
14 | /**
15 | * special layout class to handle the video streams
16 | */
17 | public class VideoGridLayout extends ViewGroup {
18 | /** resolution ratio for the streams */
19 | private static final float VIDEO_RES_RATIO = .75f;
20 | /** how many video streams in one row */
21 | private int mColumns = 4;
22 | /** how many rows of video streams */
23 | private int mRows = 2;
24 | /** size of a child */
25 | private int mChildWidth = 320, mChildHeight = 240;
26 | /** current order number - for sorting the children */
27 | private AtomicInteger mCurrentOrder = new AtomicInteger(0x100);
28 | /** ordered list of elements for one layout pass */
29 | private ArrayList mOrderedList = new ArrayList();
30 | /** the instance of the zoomed object - may be null */
31 | private View mZoomedChild = null;
32 | /** the first column of the zoomed position */
33 | private int mZoomedPosition = 0;
34 | /** the control elements to position over a zoomed element */
35 | private View mControlElements = null;
36 | /** the video display element for all streams */
37 | private View mVideoDisplay = null;
38 | /**
39 | * whether or not the grid layout actually desires a height (false), or not
40 | * (true)
41 | */
42 | private boolean mCollapsed = false;
43 |
44 | public VideoGridLayout(Context context) {
45 | super(context);
46 | }
47 |
48 | public VideoGridLayout(Context context, AttributeSet attrs) {
49 | this(context, attrs, 0);
50 | }
51 |
52 | public VideoGridLayout(Context context, AttributeSet attrs, int defStyle) {
53 | super(context, attrs, defStyle);
54 | }
55 |
56 | /**
57 | * Any layout manager that doesn't scroll will want this.
58 | */
59 | @Override
60 | public boolean shouldDelayChildPressedState() {
61 | return false;
62 | }
63 |
64 | /**
65 | * Ask all children to measure themselves and compute the measurement of
66 | * this layout based on the children.
67 | */
68 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
69 | @Override
70 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
71 | int maxWidth = View.MeasureSpec.getSize(widthMeasureSpec);
72 | mChildWidth = maxWidth / mColumns;
73 | mChildHeight = (int) (mChildWidth * VIDEO_RES_RATIO);
74 | int desiredHeight = mChildHeight * mRows;
75 |
76 | int childWidthSpecs = View.MeasureSpec.makeMeasureSpec(mChildWidth,
77 | View.MeasureSpec.EXACTLY);
78 | int childHeightSpecs = View.MeasureSpec.makeMeasureSpec(mChildHeight,
79 | View.MeasureSpec.EXACTLY);
80 | int zoomedWidthSpecs = View.MeasureSpec.makeMeasureSpec(
81 | 2 * mChildWidth, View.MeasureSpec.EXACTLY);
82 | int zoomedHeightSpecs = View.MeasureSpec.makeMeasureSpec(
83 | 2 * mChildHeight, View.MeasureSpec.EXACTLY);
84 | int count = getChildCount();
85 | int childState = 0;
86 |
87 | int slots = mColumns * mRows;
88 | for (int i = 0; i < count; ++i) {
89 | View child = getChildAt(i);
90 | if (child == mControlElements && child.getVisibility() != View.GONE) {
91 | child.measure(zoomedWidthSpecs, zoomedHeightSpecs);
92 | childState = combineMeasuredStates(childState,
93 | child.getMeasuredState());
94 | } else if (child == mVideoDisplay) {
95 | child.measure(widthMeasureSpec, heightMeasureSpec);
96 | childState = combineMeasuredStates(childState,
97 | child.getMeasuredState());
98 | } else if (slots > 0 && child.getVisibility() != View.GONE) {
99 | --slots;
100 | if (child == mZoomedChild) {
101 | child.measure(zoomedWidthSpecs, zoomedHeightSpecs);
102 | } else {
103 | child.measure(childWidthSpecs, childHeightSpecs);
104 | }
105 | childState = combineMeasuredStates(childState,
106 | child.getMeasuredState());
107 | }
108 | }
109 |
110 | if (slots >= mColumns) {
111 | int realRows = mRows - (slots / mColumns);
112 | // real rows must be at least 2, or mRows
113 | realRows = Math.max(Math.min(mRows, 2), realRows);
114 | desiredHeight = realRows * mChildHeight;
115 | }
116 | if (mCollapsed) {
117 | desiredHeight = 0;
118 | }
119 |
120 | int desiredHeightSpec = resolveSizeAndState(desiredHeight,
121 | heightMeasureSpec,
122 | childState << View.MEASURED_HEIGHT_STATE_SHIFT);
123 | setMeasuredDimension(
124 | resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
125 | desiredHeightSpec);
126 | }
127 |
128 | @Override
129 | protected void onLayout(boolean changed, int left, int top, int right,
130 | int bottom) {
131 | int parentLeft = 0;
132 | int parentTop = 0;
133 | int parentRight = right - left;
134 | int parentBottom = bottom - top;
135 |
136 | int count = getChildCount();
137 | int slots = mColumns * mRows;
138 |
139 | mOrderedList.clear();
140 | for (int i = 0; i < count; ++i) {
141 | View child = getChildAt(i);
142 | if (mOrderedList.size() == slots) {
143 | break;
144 | } else if (child == mControlElements || child == mVideoDisplay) {
145 | continue;
146 | } else if (mOrderedList.size() < slots
147 | && child.getVisibility() != View.GONE) {
148 | int curOrder = ((LayoutParams) child.getLayoutParams()).order;
149 | int k = 0;
150 | for (int n = mOrderedList.size(); k < n; ++k) {
151 | if (((LayoutParams) mOrderedList.get(k).getLayoutParams()).order >= curOrder) {
152 | break;
153 | }
154 | }
155 | mOrderedList.add(k, child);
156 | }
157 | }
158 |
159 | for (int i = 0, n = mOrderedList.size(); i < n; ++i) {
160 | View child = mOrderedList.get(i);
161 | if (child == mZoomedChild && mRows > 1) {
162 | continue;
163 | }
164 | ((LayoutParams) child.getLayoutParams()).gridPosition = i;
165 | int x = i % mColumns;
166 | int y = i / mColumns;
167 |
168 | int child_left = parentLeft + x * mChildWidth;
169 | int child_top = parentTop + y * mChildHeight;
170 | int child_right = parentLeft + (x + 1) * mChildWidth;
171 | int child_bottom = parentTop + (y + 1) * mChildHeight;
172 | child.layout(child_left, child_top, child_right, child_bottom);
173 |
174 | if (child.getVisibility() == View.INVISIBLE) {
175 | child.setVisibility(View.VISIBLE);
176 | }
177 | }
178 |
179 | synchronized (this) {
180 | // can only zoom if at least 2 rows
181 | if (mZoomedChild != null && mRows > 1 && mZoomedPosition >= 0) {
182 | int x0 = mZoomedPosition % mColumns;
183 | int y0 = mZoomedPosition / mColumns;
184 | int x1 = x0 + 2;
185 | int y1 = y0 + 2;
186 |
187 | int zoomed_left = parentLeft + x0 * mChildWidth;
188 | int zoomed_top = parentTop + y0 * mChildHeight;
189 | int zoomed_right = parentLeft + x1 * mChildWidth;
190 | int zoomed_bottom = parentTop + y1 * mChildHeight;
191 | mZoomedChild.layout(zoomed_left, zoomed_top, zoomed_right,
192 | zoomed_bottom);
193 | if (mControlElements != null) {
194 | mControlElements.layout(zoomed_left, zoomed_top,
195 | zoomed_right, zoomed_bottom);
196 | }
197 |
198 | for (int y = y0; y < y1; ++y) {
199 | for (int x = x0; x < x1; ++x) {
200 | int index = x + y * mColumns;
201 | if (index < mOrderedList.size()) {
202 | View view = mOrderedList.get(index);
203 | if (view != mZoomedChild) {
204 | view.setVisibility(View.INVISIBLE);
205 | }
206 | }
207 | }
208 | }
209 | }
210 | }
211 |
212 | mVideoDisplay.layout(parentLeft, parentTop, parentRight, parentBottom);
213 | }
214 |
215 | /** retrieve currently measured child width and height */
216 | public Point getChildSize() {
217 | return new Point(mChildWidth, mChildHeight);
218 | }
219 |
220 | /**
221 | * set the grid layout, number of columns and rows - implicitly requests a
222 | * layout pass!
223 | */
224 | public void setGridDimensions(int columns, int rows) {
225 | if (mColumns != columns || mRows != rows) {
226 | mColumns = columns;
227 | mRows = rows;
228 | requestLayout();
229 | }
230 | }
231 |
232 | public static class LayoutParams extends ViewGroup.LayoutParams {
233 | /** the information on where to sort this element */
234 | public int order = 0;
235 | /** actual position in the grid this time */
236 | int gridPosition = 0;
237 |
238 | public LayoutParams(Context c, AttributeSet attrs) {
239 | super(c, attrs);
240 | }
241 |
242 | public LayoutParams(int width, int height) {
243 | super(width, height);
244 | }
245 |
246 | public LayoutParams(ViewGroup.LayoutParams source) {
247 | super(source);
248 | }
249 |
250 | /** create layout params with given order */
251 | public LayoutParams(int order) {
252 | super(MATCH_PARENT, MATCH_PARENT);
253 | this.order = order;
254 | }
255 | }
256 |
257 | @Override
258 | public LayoutParams generateLayoutParams(AttributeSet attrs) {
259 | LayoutParams result = new LayoutParams(getContext(), attrs);
260 | result.order = mCurrentOrder.incrementAndGet();
261 | return result;
262 | }
263 |
264 | @Override
265 | protected android.view.ViewGroup.LayoutParams generateDefaultLayoutParams() {
266 | LayoutParams result = new LayoutParams(LayoutParams.MATCH_PARENT,
267 | LayoutParams.MATCH_PARENT);
268 | if (mChildHeight > 0) {
269 | result.width = mChildWidth;
270 | result.height = mChildHeight;
271 | }
272 | result.order = mCurrentOrder.incrementAndGet();
273 | return result;
274 | }
275 |
276 | @Override
277 | protected android.view.ViewGroup.LayoutParams generateLayoutParams(
278 | ViewGroup.LayoutParams p) {
279 | LayoutParams result = new LayoutParams(p);
280 | result.order = mCurrentOrder.incrementAndGet();
281 | return result;
282 | }
283 |
284 | @Override
285 | protected boolean checkLayoutParams(android.view.ViewGroup.LayoutParams p) {
286 | return p instanceof LayoutParams;
287 | }
288 |
289 | /**
290 | * signals that the given view was just tapped. This indicates the view
291 | * should switch from normal to enlarged display, or back to normal?
292 | * Implicitly calls requestLayout!
293 | *
294 | * @param v
295 | * The tapped view.
296 | * @return true if the element is now zoomed, false if it was returned to
297 | * normal size
298 | */
299 | public boolean onTapped(View v) {
300 | if (v == null || v.getParent() != this) {
301 | return false;
302 | }
303 |
304 | if (mZoomedChild != v) {
305 | setZoomedChild(v);
306 | } else {
307 | setZoomedChild(null);
308 | }
309 | requestLayout();
310 | return v == mZoomedChild;
311 | }
312 |
313 | /**
314 | * selects a child to be displayed in a zoomed way, unsets if null is passed
315 | * as parameter
316 | */
317 | public void setZoomedChild(View v) {
318 | synchronized (this) {
319 | mZoomedChild = v;
320 |
321 | if (v != null) {
322 | v.bringToFront();
323 | if (mControlElements != null) {
324 | mControlElements.bringToFront();
325 | }
326 |
327 | int gridpos = ((LayoutParams) v.getLayoutParams()).gridPosition;
328 | mZoomedPosition = gridpos % mColumns;
329 | if (mZoomedPosition >= mColumns / 2) {
330 | // move left if in right half
331 | mZoomedPosition = mZoomedPosition - 1;
332 | }
333 |
334 | // move up one row if in lower half
335 | mZoomedPosition += mColumns
336 | * (gridpos / mColumns + (gridpos / mColumns >= mRows / 2 ? -1
337 | : 0));
338 | }
339 | }
340 | }
341 |
342 | /** access current zoomed view */
343 | public View getZoomedChild() {
344 | return mZoomedChild;
345 | }
346 |
347 | /**
348 | * set a child to be considered the control elements which will always be
349 | * drawn over the zoomed child
350 | */
351 | public void setControlElements(View v) {
352 | mControlElements = v;
353 | if (v != null) {
354 | bringChildToFront(v);
355 | }
356 | }
357 |
358 | /** retrieve currently set control view */
359 | public View getControlElements() {
360 | return mControlElements;
361 | }
362 |
363 | /**
364 | * set the full background view - typically a surface view so its drawing
365 | * order is implicitly last
366 | */
367 | public void setVideoElement(View v) {
368 | mVideoDisplay = v;
369 | }
370 |
371 | /** flag to collapse or open the video grid */
372 | public void setCollapsed(boolean flag) {
373 | if (mCollapsed != flag) {
374 | mCollapsed = flag;
375 | requestLayout();
376 | }
377 | }
378 | }
379 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/licodeclient/VideoStreamPlaceholder.java:
--------------------------------------------------------------------------------
1 | package com.example.licodeclient;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 |
6 | import com.example.licodeclient.apprtc.VideoStreamsView;
7 |
8 | public class VideoStreamPlaceholder extends View {
9 | /** associated stream's id */
10 | private String mStreamId;
11 | /** the master display for all video streams */
12 | private VideoStreamsView mVsv;
13 | /** whether or not this video stream is zoomed */
14 | private boolean mZoomed = false;
15 |
16 | public VideoStreamPlaceholder(Context context, VideoStreamsView vsv,
17 | String streamId) {
18 | super(context);
19 | mVsv = vsv;
20 | mStreamId = streamId;
21 | }
22 |
23 | @Override
24 | protected void onLayout(boolean changed, int left, int top, int right,
25 | int bottom) {
26 | super.onLayout(changed, left, top, right, bottom);
27 |
28 | // if (changed)
29 | {
30 | mVsv.setStreamDimensions(mStreamId, left, top, right, bottom,
31 | mZoomed);
32 | }
33 | }
34 |
35 | /** sets the zoomed state of this placeholder view */
36 | public void setZoomed(boolean zoomed) {
37 | mZoomed = zoomed;
38 | }
39 |
40 | /** retrieve the associated stream's id */
41 | public String getStreamId() {
42 | return mStreamId;
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/licodeclient/apprtc/FramePool.java:
--------------------------------------------------------------------------------
1 | package com.example.licodeclient.apprtc;
2 | /*
3 | * libjingle
4 | * Copyright 2013, Google Inc.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * 1. Redistributions of source code must retain the above copyright notice,
10 | * this list of conditions and the following disclaimer.
11 | * 2. Redistributions in binary form must reproduce the above copyright notice,
12 | * this list of conditions and the following disclaimer in the documentation
13 | * and/or other materials provided with the distribution.
14 | * 3. The name of the author may not be used to endorse or promote products
15 | * derived from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 |
30 |
31 | import org.webrtc.VideoRenderer.I420Frame;
32 |
33 | import java.util.HashMap;
34 | import java.util.LinkedList;
35 |
36 | /**
37 | * This class acts as an allocation pool meant to minimize GC churn caused by
38 | * frame allocation & disposal. The public API comprises of just two methods:
39 | * copyFrame(), which allocates as necessary and copies, and
40 | * returnFrame(), which returns frame ownership to the pool for use by a later
41 | * call to copyFrame().
42 | *
43 | * This class is thread-safe; calls to copyFrame() and returnFrame() are allowed
44 | * to happen on any thread.
45 | */
46 | class FramePool {
47 | // Maps each summary code (see summarizeFrameDimensions()) to a list of frames
48 | // of that description.
49 | private final HashMap> availableFrames =
50 | new HashMap>();
51 | // Every dimension (e.g. width, height, stride) of a frame must be less than
52 | // this value.
53 | private static final long MAX_DIMENSION = 4096;
54 |
55 | public I420Frame takeFrame(I420Frame source) {
56 | long desc = summarizeFrameDimensions(source);
57 | I420Frame dst = null;
58 | synchronized (availableFrames) {
59 | LinkedList frames = availableFrames.get(desc);
60 | if (frames == null) {
61 | frames = new LinkedList();
62 | availableFrames.put(desc, frames);
63 | }
64 | if (!frames.isEmpty()) {
65 | dst = frames.pop();
66 | } else {
67 | dst = new I420Frame(
68 | source.width, source.height, source.yuvStrides, null);
69 | }
70 | }
71 | return dst;
72 | }
73 |
74 | public void returnFrame(I420Frame frame) {
75 | long desc = summarizeFrameDimensions(frame);
76 | synchronized (availableFrames) {
77 | LinkedList frames = availableFrames.get(desc);
78 | if (frames == null) {
79 | throw new IllegalArgumentException("Unexpected frame dimensions");
80 | }
81 | frames.add(frame);
82 | }
83 | }
84 |
85 | /** Validate that |frame| can be managed by the pool. */
86 | public static boolean validateDimensions(I420Frame frame) {
87 | return frame.width < MAX_DIMENSION && frame.height < MAX_DIMENSION &&
88 | frame.yuvStrides[0] < MAX_DIMENSION &&
89 | frame.yuvStrides[1] < MAX_DIMENSION &&
90 | frame.yuvStrides[2] < MAX_DIMENSION;
91 | }
92 |
93 | // Return a code summarizing the dimensions of |frame|. Two frames that
94 | // return the same summary are guaranteed to be able to store each others'
95 | // contents. Used like Object.hashCode(), but we need all the bits of a long
96 | // to do a good job, and hashCode() returns int, so we do this.
97 | private static long summarizeFrameDimensions(I420Frame frame) {
98 | long ret = frame.width;
99 | ret = ret * MAX_DIMENSION + frame.height;
100 | ret = ret * MAX_DIMENSION + frame.yuvStrides[0];
101 | ret = ret * MAX_DIMENSION + frame.yuvStrides[1];
102 | ret = ret * MAX_DIMENSION + frame.yuvStrides[2];
103 | return ret;
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/libvpx/LibVpxCom.java:
--------------------------------------------------------------------------------
1 | // Copyright 2012 Google Inc. All Rights Reserved.
2 | // Author: frkoenig@google.com (Fritz Koenig)
3 | package com.google.libvpx;
4 |
5 | /**
6 | * Common parts of the codec that are shared by
7 | * the encoder and decoder.
8 | */
9 | public class LibVpxCom {
10 | static {
11 | System.loadLibrary("vpx");
12 | System.loadLibrary("vpxJNI");
13 | }
14 |
15 | protected long vpxCodecIface;
16 |
17 | protected native String vpxCodecVersionStr();
18 | protected native String vpxCodecVersionExtraStr();
19 | protected native String vpxCodecBuildConfig();
20 |
21 | protected native boolean vpxCodecIsError(long ctx);
22 | protected native String vpxCodecErrToString(int err);
23 | protected native String vpxCodecError(long ctx);
24 | protected native String vpxCodecErrorDetail(long ctx);
25 |
26 | protected native long vpxCodecAllocCodec();
27 | protected native void vpxCodecFreeCodec(long cfg);
28 |
29 | protected native void vpxCodecDestroy(long ctx);
30 |
31 | public String versionString() {
32 | return vpxCodecVersionStr();
33 | }
34 |
35 | public String versionExtraString() {
36 | return vpxCodecVersionExtraStr();
37 | }
38 |
39 | public String buildConfigString() {
40 | return vpxCodecBuildConfig();
41 | }
42 |
43 | public String errToString(int err) {
44 | return vpxCodecErrToString(err);
45 | }
46 |
47 | public String errorString() {
48 | return vpxCodecError(vpxCodecIface);
49 | }
50 |
51 | public String errorDetailString() {
52 | return vpxCodecErrorDetail(vpxCodecIface);
53 | }
54 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/google/libvpx/LibVpxDec.java:
--------------------------------------------------------------------------------
1 | // Copyright 2012 Google Inc. All Rights Reserved.
2 | // Author: frkoenig@google.com (Fritz Koenig)
3 | package com.google.libvpx;
4 |
5 | /**
6 | * libvpx JNI wrapper for decoding functions.
7 | */
8 | public class LibVpxDec extends LibVpxCom {
9 | private long decCfgObj;
10 |
11 | private native long vpxCodecDecAllocCfg();
12 | private native void vpxCodecDecFreeCfg(long cfg);
13 |
14 | private native void vpxCodecDecSetThreads(long cfg, int value);
15 | private native void vpxCodecDecSetWidth(long cfg, int value);
16 | private native void vpxCodecDecSetHeight(long cfg, int value);
17 | private native int vpxCodecDecGetThreads(long cfg);
18 | private native int vpxCodecDecGetWidth(long cfg);
19 | private native int vpxCodecDecGetHeight(long cfg);
20 |
21 | private native boolean vpxCodecDecInit(long decoder, long cfg,
22 | boolean postproc, boolean ecEnabled);
23 | private native int vpxCodecDecDecode(long decoder, byte[] buf, int bufSize);
24 | private native byte[] vpxCodecDecGetFrame(long decoder, int[] widthHeight);
25 |
26 | public LibVpxDec(int width, int height,
27 | int threads,
28 | boolean postProcEnabled,
29 | boolean errorConcealmentEnabled) throws LibVpxException {
30 | decCfgObj = vpxCodecDecAllocCfg();
31 | vpxCodecIface = vpxCodecAllocCodec();
32 |
33 | if (width > 0) {
34 | vpxCodecDecSetWidth(decCfgObj, width);
35 | }
36 |
37 | if (height > 0) {
38 | vpxCodecDecSetHeight(decCfgObj, height);
39 | }
40 |
41 | if (threads > 0) {
42 | vpxCodecDecSetThreads(decCfgObj, threads);
43 | }
44 |
45 | if (!vpxCodecDecInit(vpxCodecIface, decCfgObj,
46 | postProcEnabled, errorConcealmentEnabled)) {
47 | throw new LibVpxException(vpxCodecError(vpxCodecIface));
48 | }
49 | }
50 |
51 | public LibVpxDec(boolean postProcEnabled,
52 | boolean errorConcealmentEnabled) throws LibVpxException {
53 | this(0, 0, 0, postProcEnabled, errorConcealmentEnabled);
54 | }
55 |
56 | public LibVpxDec() throws LibVpxException {
57 | this(0, 0, 0, false, false);
58 | }
59 |
60 | public byte[] decodeFrameToBuffer(byte[] rawFrame, int[] widthHeight, int[] result) throws LibVpxException {
61 | result[0] = vpxCodecDecDecode(vpxCodecIface, rawFrame, rawFrame.length);
62 | if (result[0] == 5) {
63 | return null;
64 | }
65 | if (result[0] != 0) {
66 | throw new LibVpxException(vpxCodecErrorDetail(vpxCodecIface));
67 | }
68 |
69 | return vpxCodecDecGetFrame(vpxCodecIface, widthHeight);
70 | }
71 |
72 | public void close() {
73 | vpxCodecDestroy(vpxCodecIface);
74 | vpxCodecDecFreeCfg(decCfgObj);
75 | vpxCodecFreeCodec(vpxCodecIface);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/libvpx/LibVpxEnc.java:
--------------------------------------------------------------------------------
1 | // Copyright 2012 Google Inc. All Rights Reserved.
2 | // Author: frkoenig@google.com (Fritz Koenig)
3 | package com.google.libvpx;
4 |
5 | /**
6 | * libvpx JNI wrapper for encoding functions.
7 | */
8 | public class LibVpxEnc extends LibVpxCom {
9 | // Enums from libyuv.
10 | public static final long FOURCC_I420 = 0x30323449;
11 | public static final long FOURCC_I422 = 0x32323449;
12 | public static final long FOURCC_NV21 = 0x3132564E;
13 | public static final long FOURCC_NV12 = 0x3231564E;
14 | public static final long FOURCC_YUY2 = 0x32595559;
15 | public static final long FOURCC_UYVY = 0x56595559;
16 | public static final long FOURCC_ARGB = 0x42475241;
17 | public static final long FOURCC_BGRA = 0x41524742;
18 | public static final long FOURCC_ABGR = 0x52474241;
19 | public static final long FOURCC_24BG = 0x47423432; // rgb888
20 | public static final long FOURCC_RGBA = 0x41424752;
21 | public static final long FOURCC_RGBP = 0x50424752; // bgr565.
22 | public static final long FOURCC_RGBO = 0x4F424752; // abgr1555.
23 | public static final long FOURCC_R444 = 0x34343452; // argb4444.
24 | public static final long FOURCC_YV12 = 0x32315659;
25 | public static final long FOURCC_YV16 = 0x36315659;
26 |
27 | // Enums from libvpx.
28 | public static final int VPX_IMG_FMT_YV12 = 0x301;
29 | public static final int VPX_IMG_FMT_I420 = 0x102;
30 |
31 | private native void vpxCodecEncInit(long encoder, long cfg);
32 |
33 | private native int vpxCodecEncCtlSetCpuUsed(long ctx, int value);
34 | private native int vpxCodecEncCtlSetEnableAutoAltRef(long ctx, int value);
35 | private native int vpxCodecEncCtlSetNoiseSensitivity(long ctx, int value);
36 | private native int vpxCodecEncCtlSetSharpness(long ctx, int value);
37 | private native int vpxCodecEncCtlSetStaticThreshold(long ctx, int value);
38 | private native int vpxCodecEncCtlSetTokenPartitions(long ctx, int value);
39 | private native int vpxCodecEncCtlSetARNRMaxFrames(long ctx, int value);
40 | private native int vpxCodecEncCtlSetARNRStrength(long ctx, int value);
41 | private native int vpxCodecEncCtlSetARNRType(long ctx, int value);
42 | private native int vpxCodecEncCtlSetTuning(long ctx, int value);
43 | private native int vpxCodecEncCtlSetCQLevel(long ctx, int value);
44 | private native int vpxCodecEncCtlSetMaxIntraBitratePct(long ctx, int value);
45 |
46 | private native boolean vpxCodecEncode(long ctx, byte[] frame,
47 | int fmt, long pts, long duration,
48 | long flags, long deadline);
49 | private native boolean vpxCodecConvertByteEncode(long ctx, byte[] frame,
50 | long pts, long duration,
51 | long flags, long deadline,
52 | long fourcc, int size, int rotation);
53 | private native boolean vpxCodecConvertIntEncode(long ctx, int[] frame,
54 | long pts, long duration,
55 | long flags, long deadline,
56 | long fourcc, int size, int rotation);
57 | private static native boolean vpxCodecHaveLibyuv();
58 |
59 | private native byte[] vpxCodecEncGetCxData(long ctx);
60 |
61 | public LibVpxEnc(LibVpxEncConfig cfg) throws LibVpxException {
62 | vpxCodecIface = vpxCodecAllocCodec();
63 | if (vpxCodecIface == 0) {
64 | throw new LibVpxException("Can not allocate JNI codec object");
65 | }
66 |
67 | vpxCodecEncInit(vpxCodecIface, cfg.handle());
68 | if (isError()) {
69 | String errorMsg = vpxCodecErrorDetail(vpxCodecIface);
70 | vpxCodecFreeCodec(vpxCodecIface);
71 | throw new LibVpxException(errorMsg);
72 | }
73 | }
74 |
75 | public boolean isError() {
76 | return vpxCodecIsError(vpxCodecIface);
77 | }
78 |
79 | private void throwOnError() throws LibVpxException {
80 | if (vpxCodecIsError(vpxCodecIface)) {
81 | throw new LibVpxException(vpxCodecErrorDetail(vpxCodecIface));
82 | }
83 | }
84 |
85 | public byte[] encodeFrame(
86 | byte[] frame, int fmt, long frameStart, long frameDuration, long flags, long deadline)
87 | throws LibVpxException {
88 | if (!vpxCodecEncode(vpxCodecIface, frame, fmt, frameStart, frameDuration, flags, deadline)) {
89 | throw new LibVpxException("Unable to encode frame");
90 | }
91 | throwOnError();
92 | return vpxCodecEncGetCxData(vpxCodecIface);
93 | }
94 |
95 | public byte[] convertByteEncodeFrame(
96 | byte[] frame, long frameStart, long frameDuration, long flags, long deadline, long fourcc, int rotation)
97 | throws LibVpxException {
98 | if (!vpxCodecConvertByteEncode(vpxCodecIface,
99 | frame, frameStart, frameDuration, flags, deadline, fourcc, frame.length, rotation)) {
100 | throw new LibVpxException("Unable to convert and encode frame");
101 | }
102 | throwOnError();
103 | return vpxCodecEncGetCxData(vpxCodecIface);
104 | }
105 |
106 | public byte[] convertIntEncodeFrame(
107 | int[] frame, long frameStart, long frameDuration, long flags, long deadline, long fourcc, int rotation)
108 | throws LibVpxException {
109 | if (!vpxCodecConvertIntEncode(vpxCodecIface,
110 | frame, frameStart, frameDuration, flags, deadline, fourcc, frame.length, rotation)) {
111 | throw new LibVpxException("Unable to convert and encode frame");
112 | }
113 | throwOnError();
114 | return vpxCodecEncGetCxData(vpxCodecIface);
115 | }
116 |
117 | public static boolean haveLibyuv() {
118 | return vpxCodecHaveLibyuv();
119 | }
120 |
121 | public void close() {
122 | vpxCodecDestroy(vpxCodecIface);
123 | vpxCodecFreeCodec(vpxCodecIface);
124 | }
125 |
126 | public void setCpuUsed(int value) throws LibVpxException {
127 | // TODO(frkoenig) : Investigate anonymous interface class to reduce duplication
128 | if (vpxCodecEncCtlSetCpuUsed(vpxCodecIface, value) != 0) {
129 | throw new LibVpxException("Unable to set CpuUsed");
130 | }
131 |
132 | throwOnError();
133 | }
134 |
135 | public void setEnableAutoAltRef(int value) throws LibVpxException {
136 | if (vpxCodecEncCtlSetEnableAutoAltRef(vpxCodecIface, value) != 0) {
137 | throw new LibVpxException("Unable to Enable Auto Alt Ref");
138 | }
139 |
140 | throwOnError();
141 | }
142 |
143 | public void setNoiseSensitivity(int value) throws LibVpxException {
144 | if (vpxCodecEncCtlSetNoiseSensitivity(vpxCodecIface, value) != 0) {
145 | throw new LibVpxException("Unable to set Noise Sensitivity");
146 | }
147 |
148 | throwOnError();
149 | }
150 |
151 | public void setSharpness(int value) throws LibVpxException {
152 | if (vpxCodecEncCtlSetSharpness(vpxCodecIface, value) != 0) {
153 | throw new LibVpxException("Unable to set Sharpness");
154 | }
155 |
156 | throwOnError();
157 | }
158 |
159 | public void setStaticThreshold(int value) throws LibVpxException {
160 | if (vpxCodecEncCtlSetStaticThreshold(vpxCodecIface, value) != 0) {
161 | throw new LibVpxException("Unable to set Static Threshold");
162 | }
163 |
164 | throwOnError();
165 | }
166 |
167 | public void setTokenPartitions(int value) throws LibVpxException {
168 | if (vpxCodecEncCtlSetTokenPartitions(vpxCodecIface, value) != 0) {
169 | throw new LibVpxException("Unable to set Token Partitions");
170 | }
171 |
172 | throwOnError();
173 | }
174 |
175 | public void setARNRMaxFrames(int value) throws LibVpxException {
176 | if (vpxCodecEncCtlSetARNRMaxFrames(vpxCodecIface, value) != 0) {
177 | throw new LibVpxException("Unable to set ARNR Max Frames");
178 | }
179 |
180 | throwOnError();
181 | }
182 |
183 | public void setARNRStrength(int value) throws LibVpxException {
184 | if (vpxCodecEncCtlSetARNRStrength(vpxCodecIface, value) != 0) {
185 | throw new LibVpxException("Unable to set ARNR Strength");
186 | }
187 |
188 | throwOnError();
189 | }
190 |
191 | public void setARNRType(int value) throws LibVpxException {
192 | if (vpxCodecEncCtlSetARNRType(vpxCodecIface, value) != 0) {
193 | throw new LibVpxException("Unable to set ARNRType");
194 | }
195 |
196 | throwOnError();
197 | }
198 |
199 | public void setTuning(int value) throws LibVpxException {
200 | if (vpxCodecEncCtlSetTuning(vpxCodecIface, value) != 0) {
201 | throw new LibVpxException("Unable to set Tuning");
202 | }
203 |
204 | throwOnError();
205 | }
206 |
207 | public void setCQLevel(int value) throws LibVpxException {
208 | if (vpxCodecEncCtlSetCQLevel(vpxCodecIface, value) != 0) {
209 | throw new LibVpxException("Unable to set CQLevel");
210 | }
211 |
212 | throwOnError();
213 | }
214 |
215 | public void setMaxIntraBitratePct(int value) throws LibVpxException {
216 | if (vpxCodecEncCtlSetMaxIntraBitratePct(vpxCodecIface, value) != 0) {
217 | throw new LibVpxException("Unable to set Max Intra Bitrate Pct");
218 | }
219 |
220 | throwOnError();
221 | }
222 | }
223 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/libvpx/LibVpxEncConfig.java:
--------------------------------------------------------------------------------
1 | // Copyright 2012 Google Inc. All Rights Reserved.
2 | // Author: frkoenig@google.com (Fritz Koenig)
3 | package com.google.libvpx;
4 |
5 | /**
6 | * JNI interface to C struct used for configuring
7 | * the libvpx encoder.
8 | */
9 | public class LibVpxEncConfig extends LibVpxCom {
10 | private long encCfgObj;
11 |
12 | private native long vpxCodecEncAllocCfg();
13 | private native void vpxCodecEncFreeCfg(long cfg);
14 |
15 | private native int vpxCodecEncConfigDefault(long cfg, int argUsage);
16 |
17 | private native void vpxCodecEncSetUsage(long cfg, int value);
18 | private native void vpxCodecEncSetThreads(long cfg, int value);
19 | private native void vpxCodecEncSetProfile(long cfg, int value);
20 | private native void vpxCodecEncSetWidth(long cfg, int value);
21 | private native void vpxCodecEncSetHeight(long cfg, int value);
22 | private native void vpxCodecEncSetTimebase(long cfg, int num, int den);
23 | private native void vpxCodecEncSetErrorResilient(long cfg, int value);
24 | private native void vpxCodecEncSetPass(long cfg, int value);
25 | private native void vpxCodecEncSetLagInFrames(long cfg, int value);
26 | private native void vpxCodecEncSetRCDropframeThresh(long cfg, int value);
27 | private native void vpxCodecEncSetRCResizeAllowed(long cfg, int value);
28 | private native void vpxCodecEncSetRCResizeUpThresh(long cfg, int value);
29 | private native void vpxCodecEncSetRCResizeDownThresh(long cfg, int value);
30 | private native void vpxCodecEncSetRCEndUsage(long cfg, int value);
31 | private native void vpxCodecEncSetRCTargetBitrate(long cfg, int value);
32 | private native void vpxCodecEncSetRCMinQuantizer(long cfg, int value);
33 | private native void vpxCodecEncSetRCMaxQuantizer(long cfg, int value);
34 | private native void vpxCodecEncSetRCUndershootPct(long cfg, int value);
35 | private native void vpxCodecEncSetRCOvershootPct(long cfg, int value);
36 | private native void vpxCodecEncSetRCBufSz(long cfg, int value);
37 | private native void vpxCodecEncSetRCBufInitialSz(long cfg, int value);
38 | private native void vpxCodecEncSetRCBufOptimalSz(long cfg, int value);
39 | private native void vpxCodecEncSetRC2PassVBRBiasPct(long cfg, int value);
40 | private native void vpxCodecEncSetRC2PassVBRMinsectionPct(long cfg, int value);
41 | private native void vpxCodecEncSetRC2PassVBRMaxsectioniasPct(long cfg, int value);
42 | private native void vpxCodecEncSetKFMode(long cfg, int value);
43 | private native void vpxCodecEncSetKFMinDist(long cfg, int value);
44 | private native void vpxCodecEncSetKFMaxDist(long cfg, int value);
45 |
46 | private native int vpxCodecEncGetUsage(long cfg);
47 | private native int vpxCodecEncGetThreads(long cfg);
48 | private native int vpxCodecEncGetProfile(long cfg);
49 | private native int vpxCodecEncGetWidth(long cfg);
50 | private native int vpxCodecEncGetHeight(long cfg);
51 | private native Rational vpxCodecEncGetTimebase(long cfg);
52 | private native int vpxCodecEncGetErrorResilient(long cfg);
53 | private native int vpxCodecEncGetPass(long cfg);
54 | private native int vpxCodecEncGetLagInFrames(long cfg);
55 | private native int vpxCodecEncGetRCDropframeThresh(long cfg);
56 | private native int vpxCodecEncGetRCResizeAllowed(long cfg);
57 | private native int vpxCodecEncGetRCResizeUpThresh(long cfg);
58 | private native int vpxCodecEncGetRCResizeDownThresh(long cfg);
59 | private native int vpxCodecEncGetRCEndUsage(long cfg);
60 | private native int vpxCodecEncGetRCTargetBitrate(long cfg);
61 | private native int vpxCodecEncGetRCMinQuantizer(long cfg);
62 | private native int vpxCodecEncGetRCMaxQuantizer(long cfg);
63 | private native int vpxCodecEncGetRCUndershootPct(long cfg);
64 | private native int vpxCodecEncGetRCOvershootPct(long cfg);
65 | private native int vpxCodecEncGetRCBufSz(long cfg);
66 | private native int vpxCodecEncGetRCBufInitialSz(long cfg);
67 | private native int vpxCodecEncGetRCBufOptimalSz(long cfg);
68 | private native int vpxCodecEncGetRC2PassVBRBiasPct(long cfg);
69 | private native int vpxCodecEncGetRC2PassVBRMinsectionPct(long cfg);
70 | private native int vpxCodecEncGetRC2PassVBRMaxsectioniasPct(long cfg);
71 | private native int vpxCodecEncGetKFMode(long cfg);
72 | private native int vpxCodecEncGetKFMinDist(long cfg);
73 | private native int vpxCodecEncGetKFMaxDist(long cfg);
74 |
75 | private native int vpxCodecEncGetFourcc();
76 |
77 | public LibVpxEncConfig(int width, int height) throws LibVpxException {
78 | encCfgObj = vpxCodecEncAllocCfg();
79 | if (encCfgObj == 0) {
80 | throw new LibVpxException("Can not allocate JNI encoder configure object");
81 | }
82 |
83 | int res = vpxCodecEncConfigDefault(encCfgObj, 0);
84 | if (res != 0) {
85 | vpxCodecEncFreeCfg(encCfgObj);
86 | throw new LibVpxException(errToString(res));
87 | }
88 |
89 | setWidth(width);
90 | setHeight(height);
91 |
92 | /* Change the default timebase to a high enough value so that the encoder
93 | * will always create strictly increasing timestamps.
94 | */
95 | setTimebase(1, 1000);
96 | }
97 |
98 | public void close() {
99 | vpxCodecEncFreeCfg(encCfgObj);
100 | }
101 |
102 | public long handle() {
103 | return encCfgObj;
104 | }
105 |
106 | public void setThreads(int value) {
107 | vpxCodecEncSetThreads(encCfgObj, value);
108 | }
109 |
110 | public void setProfile(int value) {
111 | vpxCodecEncSetProfile(encCfgObj, value);
112 | }
113 |
114 | public void setWidth(int value) {
115 | vpxCodecEncSetWidth(encCfgObj, value);
116 | }
117 |
118 | public void setHeight(int value) {
119 | vpxCodecEncSetHeight(encCfgObj, value);
120 | }
121 |
122 | public void setTimebase(int num, int den) {
123 | vpxCodecEncSetTimebase(encCfgObj, num, den);
124 | }
125 |
126 | public void setErrorResilient(int value) {
127 | vpxCodecEncSetErrorResilient(encCfgObj, value);
128 | }
129 |
130 | public void setPass(int value) {
131 | vpxCodecEncSetPass(encCfgObj, value);
132 | }
133 |
134 | public void setLagInFrames(int value) {
135 | vpxCodecEncSetLagInFrames(encCfgObj, value);
136 | }
137 |
138 | public void setRCDropframeThresh(int value) {
139 | vpxCodecEncSetRCDropframeThresh(encCfgObj, value);
140 | }
141 |
142 | public void setRCResizeAllowed(int value) {
143 | vpxCodecEncSetRCResizeAllowed(encCfgObj, value);
144 | }
145 |
146 | public void setRCResizeUpThresh(int value) {
147 | vpxCodecEncSetRCResizeUpThresh(encCfgObj, value);
148 | }
149 |
150 | public void setRCResizeDownThresh(int value) {
151 | vpxCodecEncSetRCResizeDownThresh(encCfgObj, value);
152 | }
153 |
154 | public void setRCEndUsage(int value) {
155 | vpxCodecEncSetRCEndUsage(encCfgObj, value);
156 | }
157 |
158 | public void setRCTargetBitrate(int value) {
159 | vpxCodecEncSetRCTargetBitrate(encCfgObj, value);
160 | }
161 |
162 | public void setRCMinQuantizer(int value) {
163 | vpxCodecEncSetRCMinQuantizer(encCfgObj, value);
164 | }
165 |
166 | public void setRCMaxQuantizer(int value) {
167 | vpxCodecEncSetRCMaxQuantizer(encCfgObj, value);
168 | }
169 |
170 | public void setRCUndershootPct(int value) {
171 | vpxCodecEncSetRCUndershootPct(encCfgObj, value);
172 | }
173 |
174 | public void setRCOvershootPct(int value) {
175 | vpxCodecEncSetRCOvershootPct(encCfgObj, value);
176 | }
177 |
178 | public void setRCBufSz(int value) {
179 | vpxCodecEncSetRCBufSz(encCfgObj, value);
180 | }
181 |
182 | public void setRCBufInitialSz(int value) {
183 | vpxCodecEncSetRCBufInitialSz(encCfgObj, value);
184 | }
185 |
186 | public void setRCBufOptimalSz(int value) {
187 | vpxCodecEncSetRCBufOptimalSz(encCfgObj, value);
188 | }
189 |
190 | public void setKFMinDist(int value) {
191 | vpxCodecEncSetKFMinDist(encCfgObj, value);
192 | }
193 |
194 | public void setKFMaxDist(int value) {
195 | vpxCodecEncSetKFMaxDist(encCfgObj, value);
196 | }
197 |
198 | public void setKFMode(int value) {
199 | vpxCodecEncSetKFMode(encCfgObj, value);
200 | }
201 |
202 | public int getThreads() {
203 | return vpxCodecEncGetThreads(encCfgObj);
204 | }
205 |
206 | public int getProfile() {
207 | return vpxCodecEncGetProfile(encCfgObj);
208 | }
209 |
210 | public int getWidth() {
211 | return vpxCodecEncGetWidth(encCfgObj);
212 | }
213 |
214 | public int getHeight() {
215 | return vpxCodecEncGetHeight(encCfgObj);
216 | }
217 |
218 | public Rational getTimebase() {
219 | return vpxCodecEncGetTimebase(encCfgObj);
220 | }
221 |
222 | public int getErrorResilient() {
223 | return vpxCodecEncGetErrorResilient(encCfgObj);
224 | }
225 |
226 | public int getPass() {
227 | return vpxCodecEncGetPass(encCfgObj);
228 | }
229 |
230 | public int getLagInFrames() {
231 | return vpxCodecEncGetLagInFrames(encCfgObj);
232 | }
233 |
234 | public int getRCDropframeThresh() {
235 | return vpxCodecEncGetRCDropframeThresh(encCfgObj);
236 | }
237 |
238 | public int getRCResizeAllowed() {
239 | return vpxCodecEncGetRCResizeAllowed(encCfgObj);
240 | }
241 |
242 | public int getRCResizeUpThresh() {
243 | return vpxCodecEncGetRCResizeUpThresh(encCfgObj);
244 | }
245 |
246 | public int getRCResizeDownThresh() {
247 | return vpxCodecEncGetRCResizeDownThresh(encCfgObj);
248 | }
249 |
250 | public int getRCEndUsage() {
251 | return vpxCodecEncGetRCEndUsage(encCfgObj);
252 | }
253 |
254 | public int getRCTargetBitrate() {
255 | return vpxCodecEncGetRCTargetBitrate(encCfgObj);
256 | }
257 |
258 | public int getRCMinQuantizer() {
259 | return vpxCodecEncGetRCMinQuantizer(encCfgObj);
260 | }
261 |
262 | public int getRCMaxQuantizer() {
263 | return vpxCodecEncGetRCMaxQuantizer(encCfgObj);
264 | }
265 |
266 | public int getRCUndershootPct() {
267 | return vpxCodecEncGetRCUndershootPct(encCfgObj);
268 | }
269 |
270 | public int getRCOvershootPct() {
271 | return vpxCodecEncGetRCOvershootPct(encCfgObj);
272 | }
273 |
274 | public int getRCBufSz() {
275 | return vpxCodecEncGetRCBufSz(encCfgObj);
276 | }
277 |
278 | public int getRCBufInitialSz() {
279 | return vpxCodecEncGetRCBufInitialSz(encCfgObj);
280 | }
281 |
282 | public int getRCBufOptimalSz() {
283 | return vpxCodecEncGetRCBufOptimalSz(encCfgObj);
284 | }
285 |
286 | public int getFourcc() {
287 | return vpxCodecEncGetFourcc();
288 | }
289 | }
290 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/libvpx/LibVpxException.java:
--------------------------------------------------------------------------------
1 | // Copyright 2012 Google Inc. All Rights Reserved.
2 | // Author: frkoenig@google.com (Fritz Koenig)
3 | package com.google.libvpx;
4 |
5 | /**
6 | *
7 | */
8 | public class LibVpxException extends Exception {
9 | private static final long serialVersionUID = 1L;
10 |
11 | public LibVpxException(String msg) {
12 | super(msg);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/libvpx/Rational.java:
--------------------------------------------------------------------------------
1 | // Copyright 2012 Google Inc. All Rights Reserved.
2 | // Author: frkoenig@google.com (Fritz Koenig)
3 | package com.google.libvpx;
4 |
5 | /**
6 | * Holds a rational number
7 | *
8 | */
9 | public class Rational {
10 | private final long num;
11 | private final long den;
12 |
13 | public Rational() {
14 | num = 0;
15 | den = 1;
16 | }
17 |
18 | public Rational(long num, long den) {
19 | this.num = num;
20 | this.den = den;
21 | }
22 |
23 | public Rational(String num, String den) {
24 | this.num = Integer.parseInt(num);
25 | this.den = Integer.parseInt(den);
26 | }
27 |
28 | public Rational multiply(Rational b) {
29 | return new Rational(num * b.num(), den * b.den());
30 | }
31 |
32 | public Rational multiply(int b) {
33 | return new Rational(num * b, den);
34 | }
35 |
36 | public Rational reciprocal() {
37 | return new Rational(den, num);
38 | }
39 |
40 | public float toFloat() {
41 | return (float) num / (float) den;
42 | }
43 |
44 | public long toLong() {
45 | // TODO(frkoenig) : consider adding rounding to the divide.
46 | return num / den;
47 | }
48 |
49 | public long num() {
50 | return num;
51 | }
52 |
53 | public long den() {
54 | return den;
55 | }
56 |
57 | public String toString() {
58 | if (den == 1) {
59 | return new String(num + "");
60 | } else {
61 | return new String(num + "/" + den);
62 | }
63 | }
64 |
65 | public String toColonSeparatedString() {
66 | return new String(num + ":" + den);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/libvpx/VpxCodecCxPkt.java:
--------------------------------------------------------------------------------
1 | // Copyright 2012 Google Inc. All Rights Reserved.
2 | // Author: frkoenig@google.com (Fritz Koenig)
3 | package com.google.libvpx;
4 |
5 | /**
6 | * Packet of data return from encoder.
7 | */
8 | public class VpxCodecCxPkt {
9 | public byte[] buffer; // compressed data buffer
10 | public long sz; // length of compressed data
11 | public long pts; // time stamp to show frame (in timebase units)
12 | long duration; // duration to show frame (in timebase units)
13 | public int flags; // flags for this frame
14 | int partitionId; // the partition id
15 | // defines the decoding order
16 | // of the partitions. Only
17 | // applicable when "output partition"
18 | // mode is enabled. First partition
19 | // has id 0
20 | public VpxCodecCxPkt(long sz) {
21 | this.sz = sz;
22 | buffer = new byte[(int) this.sz];
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi-v7a/libjingle_peerconnection_so.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonahzheng/licodeClientForAndroid/d1a63f06536c507f127a5f62dcf1b6d4a25a15e4/app/src/main/jniLibs/armeabi-v7a/libjingle_peerconnection_so.so
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonahzheng/licodeClientForAndroid/d1a63f06536c507f127a5f62dcf1b6d4a25a15e4/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonahzheng/licodeClientForAndroid/d1a63f06536c507f127a5f62dcf1b6d4a25a15e4/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/streamself.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonahzheng/licodeClientForAndroid/d1a63f06536c507f127a5f62dcf1b6d4a25a15e4/app/src/main/res/drawable-mdpi/streamself.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonahzheng/licodeClientForAndroid/d1a63f06536c507f127a5f62dcf1b6d4a25a15e4/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
8 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_videochat.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Licode + Libjingle
5 | Hello world!
6 | Settings
7 | Local.247
8 | vchat1
9 | FAIL! Not connected to video server.
10 | Connecting video
11 | Videochat OFF
12 | Videochat ON
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | repositories {
4 | jcenter()
5 | }
6 | dependencies {
7 | classpath 'com.android.tools.build:gradle:2.3.2'
8 | }
9 | }
10 |
11 | allprojects {
12 | repositories {
13 | jcenter()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/build/android-profile/profile-2017-05-25-01-04-41-608.rawproto:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonahzheng/licodeClientForAndroid/d1a63f06536c507f127a5f62dcf1b6d4a25a15e4/build/android-profile/profile-2017-05-25-01-04-41-608.rawproto
--------------------------------------------------------------------------------
/build/android-profile/profile-2017-05-25-01-04-52-096.rawproto:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonahzheng/licodeClientForAndroid/d1a63f06536c507f127a5f62dcf1b6d4a25a15e4/build/android-profile/profile-2017-05-25-01-04-52-096.rawproto
--------------------------------------------------------------------------------
/build/android-profile/profile-2017-05-25-01-05-08-141.rawproto:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonahzheng/licodeClientForAndroid/d1a63f06536c507f127a5f62dcf1b6d4a25a15e4/build/android-profile/profile-2017-05-25-01-05-08-141.rawproto
--------------------------------------------------------------------------------
/build/android-profile/profile-2017-05-25-01-07-08-188.rawproto:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonahzheng/licodeClientForAndroid/d1a63f06536c507f127a5f62dcf1b6d4a25a15e4/build/android-profile/profile-2017-05-25-01-07-08-188.rawproto
--------------------------------------------------------------------------------
/build/generated/mockable-android-19.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonahzheng/licodeClientForAndroid/d1a63f06536c507f127a5f62dcf1b6d4a25a15e4/build/generated/mockable-android-19.jar
--------------------------------------------------------------------------------
/build/intermediates/dex-cache/cache.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
20 |
21 |
22 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonahzheng/licodeClientForAndroid/d1a63f06536c507f127a5f62dcf1b6d4a25a15e4/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu May 25 01:04:27 CST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/import-summary.txt:
--------------------------------------------------------------------------------
1 | ECLIPSE ANDROID PROJECT IMPORT SUMMARY
2 | ======================================
3 |
4 | Ignored Files:
5 | --------------
6 | The following files were *not* copied into the new Gradle project; you
7 | should evaluate whether these are still needed in your project and if
8 | so manually move them:
9 |
10 | * .gitignore
11 | * LICENSE
12 | * README.md
13 | * proguard-project.txt
14 |
15 | Replaced Jars with Dependencies:
16 | --------------------------------
17 | The importer recognized the following .jar files as third party
18 | libraries and replaced them with Gradle dependencies instead. This has
19 | the advantage that more explicit version information is known, and the
20 | libraries can be updated automatically. However, it is possible that
21 | the .jar file in your project was of an older version than the
22 | dependency we picked, which could render the project not compileable.
23 | You can disable the jar replacement in the import wizard and try again:
24 |
25 | android-support-v4.jar => com.android.support:support-v4:19.1.0
26 |
27 | Moved Files:
28 | ------------
29 | Android Gradle projects use a different directory structure than ADT
30 | Eclipse projects. Here's how the projects were restructured:
31 |
32 | * AndroidManifest.xml => app\src\main\AndroidManifest.xml
33 | * libs\androidasync-1.2.6.jar => app\libs\androidasync-1.2.6.jar
34 | * libs\armeabi-v7a\libjingle_peerconnection_so.so => app\src\main\jniLibs\armeabi-v7a\libjingle_peerconnection_so.so
35 | * libs\libjingle_peerconnection.jar => app\libs\libjingle_peerconnection.jar
36 | * res\ => app\src\main\res\
37 | * src\ => app\src\main\java\
38 |
39 | Next Steps:
40 | -----------
41 | You can now build the project. The Gradle project needs network
42 | connectivity to download dependencies.
43 |
44 | Bugs:
45 | -----
46 | If for some reason your project does not build, and you determine that
47 | it is due to a bug or limitation of the Eclipse to Gradle importer,
48 | please file a bug at http://b.android.com with category
49 | Component-Tools.
50 |
51 | (This import summary is for your information only, and can be deleted
52 | after import once you are satisfied with the results.)
53 |
--------------------------------------------------------------------------------
/licodeAndroidClient-master.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | #
6 | #Thu May 25 00:33:54 CST 2017
7 | sdk.dir=D\:\\PlatformSDKs\\android-sdk-windows
8 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------