17 |
18 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in E:\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | include ':app'
23 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
22 |
23 |
24 | #546E7A
25 | #CC263238
26 | #CDDC39
27 | #66000000
28 | #f0f0f0
29 | #202020
30 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/in_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
22 |
23 |
26 |
30 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/in_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
22 |
23 |
26 |
30 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/out_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
22 |
23 |
26 |
30 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/out_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
22 |
23 |
26 |
30 |
38 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/Angelcam/API/AngelcamAPI.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.Angelcam.API;
23 |
24 | /**
25 | * Defines some Angelcam Ready constants.
26 | */
27 | public final class AngelcamAPI {
28 |
29 | /**
30 | * Hidden constructor, the class cannot be instantiated.
31 | */
32 | private AngelcamAPI() {
33 | }
34 |
35 | // Client protocol version
36 | public static final int VERSION = 0;
37 |
38 | // Connection timeout in seconds
39 | public static final int CONNECT_TIMEOUT = 10;
40 |
41 | // Default keepalive interval in seconds
42 | public static final int KEEPALIVE_INTERVAL = 60;
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_logo.xml:
--------------------------------------------------------------------------------
1 |
21 |
22 |
27 |
28 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/ui/EditTextLockedPreference.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.ui;
23 |
24 | import android.content.Context;
25 | import android.util.AttributeSet;
26 |
27 | /**
28 | * Extends {@link EditTextPreference} to lock the initial value.
29 | */
30 | public class EditTextLockedPreference extends EditTextPreference {
31 |
32 | public EditTextLockedPreference(Context context) {
33 | super(context);
34 | }
35 |
36 | public EditTextLockedPreference(Context context, AttributeSet attrs) {
37 | super(context, attrs);
38 | }
39 |
40 | public EditTextLockedPreference(Context context, AttributeSet attrs, int defStyleAttr) {
41 | super(context, attrs, defStyleAttr);
42 | }
43 |
44 | @Override
45 | protected void onClick() {
46 | callChangeListener(getText());
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/DDNS/DynuClient.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.DDNS;
23 |
24 | import android.content.Context;
25 |
26 | import org.jetbrains.annotations.NotNull;
27 |
28 | /**
29 | * Implements the Dynu client (https://www.dynu.com).
30 | */
31 | public class DynuClient extends DDNSClient {
32 | /**
33 | * Creates a new DynuClient object.
34 | *
35 | * @param context the context where the NoIpClient is used
36 | * @param hostname the public hostname handled by the DDNS service
37 | * @param username the DDNS service username
38 | * @param password the DDNS service password
39 | */
40 | public DynuClient(@NotNull Context context, String hostname, String username, String password) {
41 | super(context, hostname, username, password);
42 | mURL = "https://api.dynu.com/nic/update";
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/Mangocam/API/MangocamCommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.Mangocam.API;
23 |
24 | import org.json.JSONException;
25 |
26 | import java.io.IOException;
27 |
28 | /**
29 | * Defines the interface implemented by the Mangocam Connect protocol commands.
30 | */
31 | public interface MangocamCommand {
32 | /**
33 | * Formats the command / reply string to send to the server.
34 | *
35 | * @return the string representing the command / reply
36 | * @throws JSONException on JSON error
37 | */
38 | String get() throws JSONException;
39 |
40 | /**
41 | * Parses the command /reply received from the server.
42 | *
43 | * @param command the string representing the command / reply
44 | * @throws IOException on JSON error
45 | */
46 | void parse(String command) throws IOException;
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/DDNS/NoIpClient.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.DDNS;
23 |
24 | import android.content.Context;
25 |
26 | import org.jetbrains.annotations.NotNull;
27 |
28 | /**
29 | * Implements the NoIp client (https://my.noip.com).
30 | */
31 | public class NoIpClient extends DDNSClient {
32 | /**
33 | * Creates a new NoIpClient object.
34 | *
35 | * @param context the context where the NoIpClient is used
36 | * @param hostname the public hostname handled by the DDNS service
37 | * @param username the DDNS service username
38 | * @param password the DDNS service password
39 | */
40 | public NoIpClient(@NotNull Context context, String hostname, String username, String password) {
41 | super(context, hostname, username, password);
42 | mURL = "https://dynupdate.no-ip.com/nic/update";
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of spyNet Camera, the Android IP camera
3 | #
4 | # Copyright (C) 2016-2017 Paolo Dematteis
5 | #
6 | # spyNet Camera is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # spyNet Camera is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | #
19 | # Paolo Dematteis - spynet314@gmail.com
20 | #
21 |
22 | # Project-wide Gradle settings.
23 |
24 | # IDE (e.g. Android Studio) users:
25 | # Gradle settings configured through the IDE *will override*
26 | # any settings specified in this file.
27 |
28 | # For more details on how to configure your build environment visit
29 | # http://www.gradle.org/docs/current/userguide/build_environment.html
30 |
31 | # Specifies the JVM arguments used for the daemon process.
32 | # The setting is particularly useful for tweaking memory settings.
33 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
34 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
35 |
36 | # When configured, Gradle will run in incubating parallel mode.
37 | # This option should only be used with decoupled projects. More details, visit
38 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
39 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/DDNS/DNSdynamicClient.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.DDNS;
23 |
24 | import android.content.Context;
25 |
26 | import org.jetbrains.annotations.NotNull;
27 |
28 | /**
29 | * Implements the DNSdynamic client (http://www.dnsdynamic.org).
30 | */
31 | public class DNSdynamicClient extends DDNSClient {
32 | /**
33 | * Creates a new DNSdynamicClient object.
34 | *
35 | * @param context the context where the NoIpClient is used
36 | * @param hostname the public hostname handled by the DDNS service
37 | * @param username the DDNS service username
38 | * @param password the DDNS service password
39 | */
40 | public DNSdynamicClient(@NotNull Context context, String hostname, String username, String password) {
41 | super(context, hostname, username, password);
42 | mURL = "https://www.dnsdynamic.org/api";
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/DDNS/FreeDNSDClient.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.DDNS;
23 |
24 | import android.content.Context;
25 |
26 | import org.jetbrains.annotations.NotNull;
27 |
28 | /**
29 | * Implements the Free DNS client (http://freedns.afraid.org/dynamic).
30 | */
31 | public class FreeDNSDClient extends DDNSClient {
32 | /**
33 | * Creates a new DNSdynamicClient object.
34 | *
35 | * @param context the context where the NoIpClient is used
36 | * @param hostname the public hostname handled by the DDNS service
37 | * @param username the DDNS service username
38 | * @param password the DDNS service password
39 | */
40 | public FreeDNSDClient(@NotNull Context context, String hostname, String username, String password) {
41 | super(context, hostname, username, password);
42 | mURL = "https://sync.afraid.org/nic/update";
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/SpyNetApplication.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera;
23 |
24 | import android.app.Application;
25 |
26 | import com.github.stkent.amplify.feedback.DefaultEmailFeedbackCollector;
27 | import com.github.stkent.amplify.feedback.GooglePlayStoreFeedbackCollector;
28 | import com.github.stkent.amplify.tracking.Amplify;
29 |
30 | /**
31 | * The spyNet Camera application.
32 | */
33 | public class SpyNetApplication extends Application {
34 |
35 | @Override
36 | public void onCreate() {
37 | super.onCreate();
38 |
39 | // Initialize the Amplify library
40 | Amplify.initSharedInstance(this)
41 | //.setAlwaysShow(BuildConfig.DEBUG)
42 | .setPositiveFeedbackCollectors(new GooglePlayStoreFeedbackCollector())
43 | .setCriticalFeedbackCollectors(new DefaultEmailFeedbackCollector(getString(R.string.app_support_email)))
44 | .applyAllDefaultRules();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | apply plugin: 'com.android.application'
23 |
24 | android {
25 | compileSdkVersion 25
26 | buildToolsVersion '25.0.2'
27 | defaultConfig {
28 | applicationId "com.spynet.camtest"
29 | minSdkVersion 17
30 | targetSdkVersion 23
31 | versionCode 37
32 | versionName '2.4.6'
33 | }
34 | buildTypes {
35 | release {
36 | minifyEnabled false
37 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
38 | }
39 | }
40 | productFlavors {
41 | }
42 | }
43 |
44 | dependencies {
45 | compile fileTree(include: ['*.jar'], dir: 'libs')
46 | compile 'com.android.support:appcompat-v7:25.2.0'
47 | compile 'com.android.support:support-v4:25.2.0'
48 | compile 'org.jetbrains:annotations:13.0'
49 | compile 'com.takisoft.fix:preference-v7:25.2.0.0'
50 | compile 'com.github.stkent:amplify:2.0.0'
51 | compile 'org.bitlet:weupnp:0.1.4'
52 | }
53 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/Mangocam/API/NoopCommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.Mangocam.API;
23 |
24 | import android.content.Context;
25 |
26 | import org.jetbrains.annotations.NotNull;
27 | import org.json.JSONException;
28 |
29 | import java.io.IOException;
30 |
31 | /**
32 | * Defines the Mangocam API NOOP command.
33 | *
34 | * Command example:
35 | *
36 | * NOOP []
37 | */
38 | public class NoopCommand implements MangocamCommand {
39 |
40 | private final Context mContext;
41 |
42 | /**
43 | * Creates a new NoopCommand object.
44 | *
45 | * @param context the context where the object is used
46 | */
47 | public NoopCommand(@NotNull Context context) {
48 | mContext = context;
49 | }
50 |
51 |
52 | @Override
53 | public String get() throws JSONException {
54 | return "OK {\"cmd\":\"NOOP\"}\r\n";
55 | }
56 |
57 | @Override
58 | public void parse(String command) throws IOException {
59 | // Nothing to do
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/src/main/assets/Angelcam/ca.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIFFDCCAvwCCQD+OG2n4YvuhzANBgkqhkiG9w0BAQUFADBMMQswCQYDVQQGEwJD
3 | WjETMBEGA1UECAwKU29tZS1TdGF0ZTEPMA0GA1UEBwwGUHJhZ3VlMRcwFQYDVQQK
4 | DA5hbmdlbGNhbSwgaW5jLjAeFw0xNTAzMDUxMDIxMTBaFw0yNTAzMDIxMDIxMTBa
5 | MEwxCzAJBgNVBAYTAkNaMRMwEQYDVQQIDApTb21lLVN0YXRlMQ8wDQYDVQQHDAZQ
6 | cmFndWUxFzAVBgNVBAoMDmFuZ2VsY2FtLCBpbmMuMIICIjANBgkqhkiG9w0BAQEF
7 | AAOCAg8AMIICCgKCAgEA7nhHZxTAevpmPMVJYtmtec+mjLom4IoXgLnNj2vX59th
8 | RBPUEHBTMEozU4A3u0lZXp5nGLi/S4yVQ+I2JXCLPivh76sqUaW3aaDBVoN9B0G6
9 | lZWCCR3T9bVZSimnFn/ybnqCqpCCFK3uE5a0hBSbqwm+s0XekRkfoapOoxpwcKAZ
10 | yN8dVOXX4gcr7ZJOMJwMDBjCooUBG43zVCwGPMcbDg6tWSLTVY0cPUmlffDG+OvL
11 | GXdwsI1wT0JsHEYe3XCxl/mn8FxFInL24aiHA/XsKOuAj6P9b9Iz6kcaJYPBc0xy
12 | ecsGwFO3Cv+KbdyIFsnw+xm3J7IBHlOTeJnv6rdD3R9MOZy8bFZcFDY13B4Ikzf9
13 | 7odcWVMnM5w4uWexkOPbjfMqOqhfmFHNvL4iuoc6kYbWjNOcqj4e0O0SmQcX0oDM
14 | dZkhOAD087lNif+TNHI33KA0eCUPO65rknWiI0jT+DNuHYbKcdrIdIs+ndnPA9KB
15 | U3FIa2COwmh1Zhy/gduluthf5t8ndja6jvOEeP4HujSQumt6iCmQsKZ16ftX5nob
16 | bbHEY7BKEtMbBASTJnZ3rvBzqOmuyg+T1x2tRmTVFkyvdyaGaV++DbkHvGszw0rG
17 | BhAR0M3/HI0Ew+yg4SROGtKihQ3DXwXndADkyPespJkaMmcUERukt2KuJXRpDCkC
18 | AwEAATANBgkqhkiG9w0BAQUFAAOCAgEACupy0wOMJT2vzQgh30Cd36sH25PimImX
19 | V54nU2HbVXSXQ4w88cKkS88NeDuqvcf+n1uKxC2fnUMor0JAy0irXyddUT5SZkn3
20 | mTheasPzDG96SRVx25yIqmzHlfrDE0prangh3oBD3vrPyIWPAIVWVaZ56b3p8MTY
21 | ZdcRVQkp1fVyfLU89EBpVAQDV5roic4UD1IBHjvYRpycL31oi8FXeCTMgwhPE3GA
22 | M/EPD3NBX5wDtFWkJKrhbU+IFeDYldKzeBd1TrbfmifkoFkddSOxf89EQpnfPgxs
23 | 9XRuwZiPLuakuGvnw7FZYyzv5FoettDePuxlNsKuThe/eYTo+dL+1+OvpFm4epeI
24 | 7HPazSmSaLDYqnOakiSRyUVQEC7cSODBuwVG9hb/5NCwO1bsp/sAe2TZechV2E1p
25 | v+2XAPCWLtsNFK48OEvQ7sP/7YyOUuHP0hEgbWAe5R795MT5b1GJCikN/JNe8omk
26 | 3evPhqJg3p3439Lnr6Fcfgbj2ZSSasWcxd3XleZGweoUB6VNFBbjSjf5W573C3/o
27 | SH19jbTHRM+Q9ELqjvR/JNJp3BYUr8g+6HZoKKjSvRye2orvlyH0rg0Q0puXdrv1
28 | keEsNQUlw5QbZhNEWn7PHiRNcQkwXbRCJD8NvBKL5tdQ0fOWTk5RBnYlAbMDUd4l
29 | u8c1VUFo3So=
30 | -----END CERTIFICATE-----
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # spyNet Cloud IP Camera
2 |
3 | ### Allows to use your mobile device as an IP camera than can stream to the cloud
4 |
5 | With *spyNet Camera* it is possible to use an Android device as a wireless IP camera.
6 | This way, it is possible to renew old smartphones and tablets, realizing your own video surveillance system easily, even on the WEB.
7 | The integrated cloud support allows to access the ***angelcam*** and ***Mangocam*** services quickly,
8 | with no need to configure the router.
9 | It works with the WiFi or by using the mobile data connectivity.
10 |
11 | ### Main features:
12 |
13 | * H264 and MJPEG video formats
14 | * AAC audio formats
15 | * HTTP, RTSP, RTSP over TCP and RTSP over HTTP protocols
16 | * UPnP support
17 | * integrated support for the ***angelcam*** and ***Mangocam*** cloud services
18 | * compatibility with standard VCR and online services
19 | * streaming available even with the screen off and the device sleeping
20 | * background streaming when the app is closed
21 | * discreet monotoring by simulating a digital photo-frame, while streaming the front camera
22 | * integrated server to allow accessibility on the local network
23 | * can stream any available camera
24 | * *Screen Capture* (aka screencast) to stream the screen content
25 | * selectable video resolution and quality
26 | * selectable audio quality and gain
27 | * interactive zoom and focus control
28 | * JSON API
29 | * no ads, no restrictions, absolutely for free
30 |
31 | ### Get involved
32 |
33 | You are encouraged to verify the code, to propose changes or bug fixes
34 | and to translate the messages in your own language.
35 |
36 | ### Disclaimer
37 |
38 | According to the GPL license, you are the welcome in browsing, downloading and editing the spyNet Camera source code, maybe to create your own version.
39 | Anyway, the only official version will be the one that can be downloaded from the Google Play Store.
40 | The author is not responsible of any other version other than the official one.
41 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/Mangocam/API/MangocamAPI.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.Mangocam.API;
23 |
24 | /**
25 | * Defines some Mangocam Connect constants.
26 | */
27 | public final class MangocamAPI {
28 |
29 | /**
30 | * Hidden constructor, the class cannot be instantiated.
31 | */
32 | private MangocamAPI() {
33 | }
34 |
35 | // Client protocol version
36 | public static final double VERSION = 1.0;
37 |
38 | // Base URL to access API
39 | public static final String BASE_URL = "/api/v2/upload/";
40 |
41 | // Connection timeout in seconds
42 | public static final int CONNECT_TIMEOUT = 10;
43 |
44 | // Default keepalive interval in seconds
45 | public static final int KEEPALIVE_INTERVAL = 30;
46 |
47 | // Maximum allowed bandwidth in kbps
48 | public static final int MAX_BANDWIDTH = 1000;
49 |
50 | // Maximum allowed MJPEG fps
51 | public static final int MJPEG_MAX_FPS = 5;
52 |
53 | // Default delay, in seconds, after which to stop sending and start again autonomously
54 | public static final int MJPEG_SPLIT_SECS = 5;
55 | }
56 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/ui/EditTextPreference.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.ui;
23 |
24 | import android.content.Context;
25 | import android.util.AttributeSet;
26 |
27 | /**
28 | * Extends {@link com.takisoft.fix.support.v7.preference.EditTextPreference} to automatically
29 | * update the summary.
30 | */
31 | public class EditTextPreference extends com.takisoft.fix.support.v7.preference.EditTextPreference {
32 |
33 | private CharSequence mSummary;
34 |
35 | public EditTextPreference(Context context) {
36 | super(context);
37 | mSummary = super.getSummary();
38 | }
39 |
40 | public EditTextPreference(Context context, AttributeSet attrs) {
41 | super(context, attrs);
42 | mSummary = super.getSummary();
43 | }
44 |
45 | public EditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {
46 | super(context, attrs, defStyleAttr);
47 | mSummary = super.getSummary();
48 | }
49 |
50 | @Override
51 | public void setText(String text) {
52 | super.setText(text);
53 | if (mSummary != null)
54 | setSummary(String.format(mSummary.toString(), text == null ? "" : text));
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/Angelcam/API/PingMessage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.Angelcam.API;
23 |
24 | import java.io.InvalidObjectException;
25 |
26 | /**
27 | * Defines the Arrow protocol PING message.
28 | * Ping request used for connection health checks.
29 | * It is periodically sent by both server and client.
30 | * The message contains no data.
31 | */
32 | public class PingMessage extends ControlMessage {
33 |
34 | /**
35 | * Creates a new PingMessage object.
36 | *
37 | * @param messageID message ID, used for request/response pairing
38 | */
39 | public PingMessage(int messageID, int errorCode) {
40 | super(messageID, TYPE_PING);
41 | }
42 |
43 | /**
44 | * Wraps a PingMessage object around a ControlMessage object.
45 | *
46 | * @param message the original ControlMessage object
47 | * @throws InvalidObjectException if the {@code message} doesn't match
48 | */
49 | public PingMessage(ControlMessage message) throws InvalidObjectException {
50 | super(message.mMessageID, message.mType);
51 | if (mType != TYPE_PING)
52 | throw new InvalidObjectException("The message is not a PING message");
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_slideshow.xml:
--------------------------------------------------------------------------------
1 |
21 |
22 |
27 |
28 |
32 |
33 |
39 |
40 |
41 |
42 |
46 |
47 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/Mangocam/API/StatsCommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.Mangocam.API;
23 |
24 | import android.content.Context;
25 |
26 | import org.jetbrains.annotations.NotNull;
27 | import org.json.JSONException;
28 | import org.json.JSONObject;
29 |
30 | import java.io.IOException;
31 |
32 | /**
33 | * Defines the Mangocam API STATS command.
34 | *
35 | * Command example:
36 | *
37 | * STATS []
38 | */
39 | public class StatsCommand implements MangocamCommand {
40 |
41 | private final Context mContext;
42 | private final long mUptime;
43 | private final boolean mUploading;
44 |
45 | /**
46 | * Creates a new InfoCommand object.
47 | *
48 | * @param context the context where the object is used
49 | * @param uptime how long the client is on in seconds
50 | * @param uploading whether the client is uploading images to the server
51 | */
52 | public StatsCommand(@NotNull Context context, long uptime, boolean uploading) {
53 | mContext = context;
54 | mUptime = uptime;
55 | mUploading = uploading;
56 | }
57 |
58 | @Override
59 | public String get() throws JSONException {
60 | JSONObject jObject = new JSONObject();
61 | jObject.put("cmd", "STATS");
62 | jObject.put("uptime", mUptime);
63 | jObject.put("uploading", mUploading ? 1 : 0);
64 | return "OK " + jObject.toString() + "\r\n";
65 | }
66 |
67 | @Override
68 | public void parse(String command) throws IOException {
69 | // Nothing to do
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/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 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
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 Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
22 |
23 |
24 |
25 |
33 |
34 |
41 |
42 |
45 |
46 |
54 |
55 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
52 |
53 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/Angelcam/API/StatusMessage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.Angelcam.API;
23 |
24 | import java.io.ByteArrayOutputStream;
25 | import java.io.IOException;
26 |
27 | /**
28 | * Defines the Arrow protocol STATUS message.
29 | * Response for the GET_STATUS request. It is sent by client.
30 | */
31 | public class StatusMessage extends ControlMessage {
32 |
33 | private final int mFlags; // Client status flags
34 | private final int mActiveSessions; // Active sessions
35 |
36 | /**
37 | * Creates a new StatusMessage object.
38 | *
39 | * @param messageID message ID, used for request/response pairing
40 | * @param flags client status flags
41 | * @param sessions number of active sessions
42 | */
43 | public StatusMessage(int messageID, int flags, int sessions) {
44 | super(messageID, TYPE_STATUS);
45 | mFlags = flags;
46 | mActiveSessions = sessions;
47 | }
48 |
49 | @Override
50 | public byte[] toByteArray() throws IOException {
51 |
52 | ByteArrayOutputStream buffer = new ByteArrayOutputStream();
53 |
54 | // request_id - unsigned integer
55 | buffer.write(mMessageID >> 8);
56 | buffer.write(mMessageID);
57 | // status_flags
58 | buffer.write(mFlags >> 24);
59 | buffer.write(mFlags >> 16);
60 | buffer.write(mFlags >> 8);
61 | buffer.write(mFlags);
62 | // active_sessions - unsigned integer
63 | buffer.write(mActiveSessions >> 24);
64 | buffer.write(mActiveSessions >> 16);
65 | buffer.write(mActiveSessions >> 8);
66 | buffer.write(mActiveSessions);
67 |
68 | mData = buffer.toByteArray();
69 | return super.toByteArray();
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/media/ByteArrayInputBitStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.media;
23 |
24 | import java.io.ByteArrayInputStream;
25 |
26 | /**
27 | * A specialized {@link ByteArrayInputStream} for reading the contents of a byte array
28 | * as a bitstream.
29 | */
30 | public class ByteArrayInputBitStream extends ByteArrayInputStream {
31 |
32 | private int mAvail = 0; // Number of available bits in mData
33 | private int mData; // Next bits to consume (from a previous call)
34 |
35 | /**
36 | * Constructs a new ByteArrayInputBitStream on the byte array buf.
37 | *
38 | * @param buf the byte array to stream over.
39 | */
40 | public ByteArrayInputBitStream(byte[] buf) {
41 | super(buf);
42 | }
43 |
44 | /**
45 | * Reads some bits from the stream, starting from the MSB.
46 | *
47 | * @param bits number of bits to get, in the range 1-32
48 | * @return the bits read or -1 if the end of this stream has been reached.
49 | */
50 | public synchronized int read(int bits) {
51 |
52 | long res = 0;
53 | int left = bits;
54 | int pos = 32;
55 |
56 | if (bits < 1 || bits > 32)
57 | throw new IllegalArgumentException("bits not in range 1 to 32");
58 |
59 | while (true) {
60 | if (mAvail > 0) {
61 | pos -= mAvail;
62 | res |= (mData << pos) & 0xFFFFFFFFL;
63 | if (left > mAvail) {
64 | left -= mAvail;
65 | } else {
66 | mAvail -= left;
67 | return (int) (res >> (32 - bits));
68 | }
69 | }
70 | if ((mData = read()) == -1)
71 | return -1;
72 | mAvail = 8;
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/Mangocam/API/ReconnectCommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.Mangocam.API;
23 |
24 | import android.content.Context;
25 | import android.util.JsonReader;
26 |
27 | import org.jetbrains.annotations.NotNull;
28 | import org.json.JSONException;
29 |
30 | import java.io.IOException;
31 | import java.io.StringReader;
32 |
33 | /**
34 | * Defines the Mangocam API RECONNECT command.
35 | * Forces connection to a new host.
36 | */
37 | public class ReconnectCommand implements MangocamCommand {
38 |
39 | private final Context mContext;
40 | private String mHost = null;
41 |
42 | /**
43 | * Creates a new ReconnectCommand object.
44 | *
45 | * @param context the context where the object is used
46 | */
47 | public ReconnectCommand(@NotNull Context context) {
48 | mContext = context;
49 | }
50 |
51 | @Override
52 | public String get() throws JSONException {
53 | return "OK {\"cmd\":\"RECONNECT\"}\r\n";
54 | }
55 |
56 | @Override
57 | public void parse(String command) throws IOException {
58 | if (!command.startsWith("RECONNECT "))
59 | throw new IllegalArgumentException("wrong command");
60 | command = command.substring(10);
61 | JsonReader jr = new JsonReader(new StringReader(command));
62 | jr.beginObject();
63 | while (jr.hasNext()) {
64 | switch (jr.nextName()) {
65 | case "host":
66 | mHost = jr.nextString();
67 | break;
68 | default:
69 | jr.skipValue();
70 | }
71 | }
72 | jr.endObject();
73 | }
74 |
75 | /**
76 | * @return the host to send MJPEG to
77 | */
78 | public String getHost() {
79 | return mHost;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/media/DummySurfaceHolder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.media;
23 |
24 | import android.graphics.Canvas;
25 | import android.graphics.Rect;
26 | import android.view.Surface;
27 | import android.view.SurfaceHolder;
28 |
29 | /**
30 | * Implements a dummy SurfaceHolder that holds an already exiting Surface.
31 | */
32 | public class DummySurfaceHolder implements SurfaceHolder {
33 |
34 | private final Surface mSurface;
35 |
36 | /**
37 | * Creates a new DummySurfaceHolder object.
38 | *
39 | * @param surface the Surface to hold
40 | */
41 | public DummySurfaceHolder(Surface surface) {
42 | mSurface = surface;
43 | }
44 |
45 | @Override
46 | public void addCallback(Callback callback) {
47 | }
48 |
49 | @Override
50 | public void removeCallback(Callback callback) {
51 | }
52 |
53 | @Override
54 | public boolean isCreating() {
55 | return false;
56 | }
57 |
58 | @Override
59 | public void setType(int type) {
60 | }
61 |
62 | @Override
63 | public void setFixedSize(int width, int height) {
64 | }
65 |
66 | @Override
67 | public void setSizeFromLayout() {
68 | }
69 |
70 | @Override
71 | public void setFormat(int format) {
72 | }
73 |
74 | @Override
75 | public void setKeepScreenOn(boolean screenOn) {
76 | }
77 |
78 | @Override
79 | public Canvas lockCanvas() {
80 | return null;
81 | }
82 |
83 | @Override
84 | public Canvas lockCanvas(Rect dirty) {
85 | return null;
86 | }
87 |
88 | @Override
89 | public void unlockCanvasAndPost(Canvas canvas) {
90 | }
91 |
92 | @Override
93 | public Rect getSurfaceFrame() {
94 | return null;
95 | }
96 |
97 | @Override
98 | public Surface getSurface() {
99 | return mSurface;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/common/TimeStamp.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.common;
23 |
24 | /**
25 | * A collection of functions to handle the timestamp.
26 | */
27 | public final class TimeStamp {
28 |
29 | // Number of milliseconds between Jan 1, 1900 and Jan 1, 1970 (70 years plus 17 leap days)
30 | private static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L * 1000L;
31 |
32 | /**
33 | * Hidden constructor, the class cannot be instantiated.
34 | */
35 | private TimeStamp() {
36 | }
37 |
38 | /**
39 | * Returns the current high-resolution timestamp, in microseconds.
40 | * This method can only be used to measure elapsed time and is not related to any other notion
41 | * of system or wall-clock time. The value returned represents microseconds since some fixed but
42 | * arbitrary origin time (perhaps in the future, so values may be negative).
43 | * The same origin is used by all invocations of this method.
44 | *
45 | * @return the current timestamp in microseconds
46 | */
47 | public static long getTimeStamp() {
48 | return System.nanoTime() / 1000L;
49 | }
50 |
51 | /**
52 | * Returns the current timestamp in NTP format (RFC-1305).
53 | * NTP timestamps are represented as a 64-bit unsigned fixed-point number, in seconds relative to
54 | * 0h on 1 January 1900. The integer part is in the first 32 bits and the fraction part in the
55 | * last 32 bits. In the fraction part, the non-significant low-order bits should be set to 0.
56 | *
57 | * @return the current NTP timestamp
58 | */
59 | public static long getNTPTimeStamp() {
60 | long timeMillis = System.currentTimeMillis() + OFFSET_1900_TO_1970;
61 | long timeSeconds = timeMillis / 1000L;
62 | long timeFraction = timeMillis - timeSeconds * 1000L;
63 | return (timeSeconds << 32) | (((timeFraction << 32) / 1000L) & 0xFFFFFFFFL);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/app/src/main/aidl/com/spynet/camera/services/IStreamServiceCallBack.aidl:
--------------------------------------------------------------------------------
1 | package com.spynet.camera.services;
2 |
3 | /**
4 | * Interface defining the methods that the StreamService uses to communicate with the client.
5 | */
6 | interface IStreamServiceCallBack {
7 | /**
8 | * Notifies that the streaming has started.
9 | */
10 | oneway void onStreamingStarted();
11 |
12 | /**
13 | * Notifies that the streaming has stopped.
14 | */
15 | oneway void onStreamingStopped();
16 |
17 | /**
18 | * Notifies that the audio streaming has started.
19 | */
20 | oneway void onAudioStarted();
21 |
22 | /**
23 | * Notifies that the audio streaming has stopped.
24 | */
25 | oneway void onAudioStopped();
26 |
27 | /**
28 | * Notifies that an adapter has connected to its server.
29 | *
30 | * @param adapter the adapter name
31 | */
32 | oneway void onAdapterConnected(in String adapter);
33 |
34 | /**
35 | * Notifies that an adapter has disconnected from the server.
36 | *
37 | * @param adapter the adapter name
38 | */
39 | oneway void onAdapterDisconnected(in String adapter);
40 |
41 | /**
42 | * Notifies that an action has been requested by a client.
43 | *
44 | * @param code the log code
45 | * @param message the log message
46 | */
47 | oneway void onLog(int code, in String message);
48 |
49 | /**
50 | * Notifies that the frame size changed.
51 | *
52 | * @param size the frame size in pixels
53 | */
54 | oneway void onFrameSizeChanged(in Point size);
55 |
56 | /**
57 | * Notifies that the bitrate changed.
58 | *
59 | * @param video the video bitrate
60 | * @param audio the audio bitrate
61 | */
62 | oneway void onBitrateChanged(int video, int audio);
63 |
64 | /**
65 | * Notifies that a new zoom has been set.
66 | *
67 | * @param zoom the new zoom factor
68 | */
69 | oneway void onZoom(float zoom);
70 |
71 | /**
72 | * Called when the torch state changes.
73 | *
74 | * @param state {@code true} if the torch is on, {@code false} if it is off
75 | */
76 | oneway void onTorch(boolean state);
77 |
78 | /**
79 | * Notifies that a new mute state has been set.
80 | *
81 | * @param mute the new mute state
82 | */
83 | oneway void onMute(boolean mute);
84 |
85 | /**
86 | * Notifies that a new frame rate value is available.
87 | *
88 | * @param fps the new frame rate value
89 | */
90 | oneway void onFrameRate(float fps);
91 |
92 | /**
93 | * Called when the screen capture has been denied or authorized by the user.
94 | *
95 | * @param authorized whether the screen capture has been authorized by the user
96 | */
97 | oneway void onScreenCapture(boolean authorized);
98 | }
99 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/Mangocam/API/InfoCommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.Mangocam.API;
23 |
24 | import android.content.Context;
25 |
26 | import org.jetbrains.annotations.NotNull;
27 | import org.json.JSONException;
28 | import org.json.JSONObject;
29 |
30 | import java.io.IOException;
31 | import java.util.Calendar;
32 | import java.util.TimeZone;
33 |
34 | /**
35 | * Defines the Mangocam API INFO command.
36 | *
37 | * Command example:
38 | *
39 | * INFO []
40 | */
41 | public class InfoCommand implements MangocamCommand {
42 |
43 | private final Context mContext;
44 | private final int mImageWidth, mImageHeight;
45 |
46 | /**
47 | * Creates a new InfoCommand object.
48 | *
49 | * @param context the context where the object is used
50 | * @param width image width
51 | * @param height image height
52 | */
53 | public InfoCommand(@NotNull Context context, int width, int height) {
54 | mContext = context;
55 | mImageWidth = width;
56 | mImageHeight = height;
57 | }
58 |
59 | @Override
60 | public String get() throws JSONException {
61 | JSONObject jObject = new JSONObject();
62 | jObject.put("cmd", "INFO");
63 | jObject.put("vendor", "spyNet");
64 | jObject.put("s_ver", com.spynet.camera.BuildConfig.VERSION_NAME);
65 | jObject.put("os_name", "Android");
66 | jObject.put("os_ver", android.os.Build.VERSION.RELEASE);
67 | Calendar cal = Calendar.getInstance();
68 | TimeZone tz = cal.getTimeZone();
69 | jObject.put("tz", tz.getID());
70 | jObject.put("max_res_x", mImageWidth);
71 | jObject.put("max_res_y", mImageHeight);
72 | jObject.put("aspect", Math.floor((double) mImageWidth / (double) mImageHeight * 100.0) / 100.0);
73 | return "OK " + jObject.toString() + "\r\n";
74 | }
75 |
76 | @Override
77 | public void parse(String command) throws IOException {
78 | // Nothing to do
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/Angelcam/API/RedirectMessage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.Angelcam.API;
23 |
24 | import java.io.InvalidObjectException;
25 |
26 | /**
27 | * Defines the Arrow protocol REDIRECT message.
28 | * The message can be sent by server to redirect a client to another server. No ACK is expected, the
29 | * server closes connection immediately after sending the redirect command. Message data consist
30 | * of a "host:port" NULL terminated string.
31 | */
32 | public class RedirectMessage extends ControlMessage {
33 |
34 | private final String mHost; // Host
35 | private final int mPort; // Port
36 |
37 | /**
38 | * Wraps a RedirectMessage object around a ControlMessage object.
39 | *
40 | * @param message the original ControlMessage object
41 | * @throws InvalidObjectException if the {@code message} doesn't match
42 | */
43 | public RedirectMessage(ControlMessage message) throws InvalidObjectException {
44 | super(message.mMessageID, message.mType);
45 | if (mType != TYPE_REDIRECT)
46 | throw new InvalidObjectException("the message is not a REDIRECT message");
47 | if (message.mData == null)
48 | throw new InvalidObjectException("the message has no data");
49 | if (message.mData.length < 2 || message.mData[message.mData.length - 1] != 0)
50 | throw new InvalidObjectException("the message contains invalid data");
51 | String host = new String(message.mData, 0, message.mData.length - 1);
52 | String[] c = host.split(":");
53 | if (c.length != 2)
54 | throw new InvalidObjectException("the message contains invalid data");
55 | mHost = c[0];
56 | mPort = Integer.parseInt(c[1]);
57 | }
58 |
59 | /**
60 | * @return the host name
61 | */
62 | public String getHost() {
63 | return mHost;
64 | }
65 |
66 | /**
67 | * @return the port number
68 | */
69 | public int getPort() {
70 | return mPort;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/ui/ServiceFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.ui;
23 |
24 | import android.content.Context;
25 | import android.support.v4.app.Fragment;
26 | import android.content.ServiceConnection;
27 | import android.os.Bundle;
28 |
29 | import com.spynet.camera.services.IStreamService;
30 |
31 | /**
32 | * Defines a retained Fragment where to store {@link com.spynet.camera.services.StreamService}
33 | * references, to keep them persistent between Activity recreation.
34 | */
35 | public class ServiceFragment extends Fragment {
36 |
37 | private Context mContext;
38 | private ServiceConnection mConnection;
39 | private IStreamService mService;
40 |
41 | @Override
42 | public void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | setRetainInstance(true);
45 | }
46 |
47 | @Override
48 | public void onAttach(Context context) {
49 | super.onAttach(context);
50 | mContext = context;
51 | }
52 |
53 | @Override
54 | public void onDetach() {
55 | super.onDetach();
56 | mContext = null;
57 | }
58 |
59 | /**
60 | * @return the {@link Context} the fragment is attached to
61 | */
62 | public Context getContext() {
63 | return mContext;
64 | }
65 |
66 | /**
67 | * Stores a {@link ServiceConnection} reference.
68 | */
69 | public void setServiceConnection(ServiceConnection connection) {
70 | mConnection = connection;
71 | }
72 |
73 | /**
74 | * @return the {@link ServiceConnection} previously stored by setServiceConnection()
75 | */
76 | public ServiceConnection getServiceConnection() {
77 | return mConnection;
78 | }
79 |
80 | /**
81 | * Stores a {@link IStreamService} reference.
82 | */
83 | public void setStreamService(IStreamService service) {
84 | mService = service;
85 | }
86 |
87 | /**
88 | * @return the {@link IStreamService} previously stored by setStreamService()
89 | */
90 | public IStreamService getStreamService() {
91 | return mService;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_status.xml:
--------------------------------------------------------------------------------
1 |
21 |
22 |
29 |
30 |
39 |
40 |
49 |
50 |
59 |
60 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
22 |
23 |
29 |
30 |
49 |
50 |
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/ui/ScreenCaptureRequestActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.ui;
23 |
24 | import android.content.Context;
25 | import android.content.Intent;
26 | import android.media.projection.MediaProjectionManager;
27 | import android.support.v7.app.AppCompatActivity;
28 | import android.os.Bundle;
29 | import android.util.Log;
30 |
31 | import com.spynet.camera.media.Recorder;
32 |
33 | import org.jetbrains.annotations.NotNull;
34 |
35 | /**
36 | * An {@link android.app.Activity} that will fire the screen capture request
37 | * to the user.
38 | */
39 | public class ScreenCaptureRequestActivity extends AppCompatActivity {
40 |
41 | private static final int SCREEN_CAPTURE_REQUEST_ID = 2536;
42 |
43 | private final String TAG = getClass().getSimpleName();
44 |
45 | /**
46 | * Factory method that makes an explicit intent used to start the
47 | * ScreenCaptureRequestActivity.
48 | *
49 | * @param context the context in which the Activity will execute
50 | * @return the created Intent
51 | */
52 | @NotNull
53 | public static Intent MakeIntent(Context context) {
54 | return new Intent(context, ScreenCaptureRequestActivity.class);
55 | }
56 |
57 | @Override
58 | protected void onCreate(Bundle savedInstanceState) {
59 | super.onCreate(savedInstanceState);
60 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
61 | MediaProjectionManager manager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
62 | startActivityForResult(manager.createScreenCaptureIntent(), SCREEN_CAPTURE_REQUEST_ID);
63 | } else {
64 | Log.w(TAG, "Media projection requires API " + android.os.Build.VERSION_CODES.LOLLIPOP);
65 | finish();
66 | }
67 | }
68 |
69 | @Override
70 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
71 | if (requestCode == SCREEN_CAPTURE_REQUEST_ID) {
72 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
73 | Intent intent = new Intent(Recorder.ACTION_START_SCREEN_CAPTURE);
74 | intent.putExtra(Recorder.EXTRA_MEDIA_PROJECTION_RESULT, resultCode);
75 | intent.putExtra(Recorder.EXTRA_MEDIA_PROJECTION_INTENT, data);
76 | sendBroadcast(intent);
77 | }
78 | finish();
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
21 |
22 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
47 |
48 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
69 |
70 |
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/Mangocam/API/StopMJPEGCommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.Mangocam.API;
23 |
24 | import android.content.Context;
25 | import android.util.JsonReader;
26 |
27 | import org.jetbrains.annotations.NotNull;
28 | import org.json.JSONException;
29 |
30 | import java.io.IOException;
31 | import java.io.StringReader;
32 |
33 | /**
34 | * Defines the Mangocam API STOP_MJPEG command.
35 | *
36 | * Command example:
37 | *
38 | * STOP_MJPEG {"host":"www107.mangocam.com","task":"201007331","node":"107"}
39 | */
40 | public class StopMJPEGCommand implements MangocamCommand {
41 |
42 | private final Context mContext;
43 | private String mHost;
44 | private int mNode;
45 | private int mTask;
46 |
47 | /**
48 | * Creates a new StatsCommand object.
49 | *
50 | * @param context the context where the object is used
51 | */
52 | public StopMJPEGCommand(@NotNull Context context) {
53 | mContext = context;
54 | }
55 |
56 | @Override
57 | public String get() throws JSONException {
58 | return "OK {\"cmd\":\"STOP_MJPEG\"}\r\n";
59 | }
60 |
61 | @Override
62 | public void parse(String command) throws IOException {
63 | if (!command.startsWith("STOP_MJPEG "))
64 | throw new IllegalArgumentException("wrong command");
65 | command = command.substring(11);
66 | JsonReader jr = new JsonReader(new StringReader(command));
67 | jr.beginObject();
68 | while (jr.hasNext()) {
69 | switch (jr.nextName()) {
70 | case "host":
71 | mHost = jr.nextString();
72 | break;
73 | case "node":
74 | mNode = jr.nextInt();
75 | break;
76 | case "task":
77 | mTask = jr.nextInt();
78 | break;
79 | default:
80 | jr.skipValue();
81 | }
82 | }
83 | jr.endObject();
84 | }
85 |
86 | /**
87 | * @return the host to send MJPEG to
88 | */
89 | public String getHost() {
90 | return mHost;
91 | }
92 |
93 | /**
94 | * @return the node
95 | */
96 | public int getNode() {
97 | return mNode;
98 | }
99 |
100 | /**
101 | * @return the task ID, used by the upload server, the client will just relay
102 | */
103 | public int getTask() {
104 | return mTask;
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/gl/Shader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.gl;
23 |
24 | import android.opengl.GLES20;
25 |
26 | /**
27 | * Allows to create an OpenGL program by compiling and linking a given vertex shader
28 | * and a fragment shader.
29 | */
30 | public class Shader {
31 |
32 | /**
33 | * The program object.
34 | */
35 | public final int program;
36 |
37 | /**
38 | * Creates a new Shader object.
39 | *
40 | * @param vertexShaderSource the vertex shader source code
41 | * @param fragmentShaderSource the fragment shader source code
42 | */
43 | public Shader(String vertexShaderSource, String fragmentShaderSource) {
44 |
45 | int[] result = new int[1];
46 | String infoLog;
47 |
48 | // Build and compile vertex shader
49 | int vertexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
50 | GLES20.glShaderSource(vertexShader, vertexShaderSource);
51 | GLES20.glCompileShader(vertexShader);
52 | GLES20.glGetShaderiv(vertexShader, GLES20.GL_COMPILE_STATUS, result, 0);
53 | if (result[0] == 0) {
54 | infoLog = GLES20.glGetShaderInfoLog(vertexShader);
55 | throw new RuntimeException(infoLog);
56 | }
57 |
58 | // Build and compile fragment shader
59 | int fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
60 | GLES20.glShaderSource(fragmentShader, fragmentShaderSource);
61 | GLES20.glCompileShader(fragmentShader);
62 | GLES20.glGetShaderiv(fragmentShader, GLES20.GL_COMPILE_STATUS, result, 0);
63 | if (result[0] == 0) {
64 | infoLog = GLES20.glGetShaderInfoLog(fragmentShader);
65 | throw new RuntimeException(infoLog);
66 | }
67 |
68 | // Link shaders
69 | program = GLES20.glCreateProgram();
70 | GLES20.glAttachShader(program, vertexShader);
71 | GLES20.glAttachShader(program, fragmentShader);
72 | GLES20.glLinkProgram(program);
73 | GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, result, 0);
74 | if (result[0] == 0) {
75 | infoLog = GLES20.glGetProgramInfoLog(vertexShader);
76 | throw new RuntimeException(infoLog);
77 | }
78 |
79 | // Delete the shaders as they're linked into our program now and no longer necessary
80 | GLES20.glDeleteShader(vertexShader);
81 | GLES20.glDeleteShader(fragmentShader);
82 | }
83 |
84 | /**
85 | * Use the program by calling {@code glUseProgram(program)}.
86 | */
87 | public void use() {
88 | GLES20.glUseProgram(program);
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/media/CameraInfo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.media;
23 |
24 | import android.graphics.Point;
25 | import android.os.Parcel;
26 | import android.os.Parcelable;
27 |
28 | import java.util.ArrayList;
29 | import java.util.List;
30 |
31 | /**
32 | * Defines a {@link Parcelable} camera information container.
33 | */
34 | public class CameraInfo implements Parcelable {
35 |
36 | private final String mDescription;
37 | private final int mCameraId;
38 | private final List mSupportedPreviewSizes;
39 |
40 | /**
41 | * Creates a new CameraInfo object from Parcel.
42 | *
43 | * @param in the input Parcel
44 | */
45 | protected CameraInfo(Parcel in) {
46 | mDescription = in.readString();
47 | mCameraId = in.readInt();
48 | mSupportedPreviewSizes = new ArrayList<>();
49 | in.readTypedList(mSupportedPreviewSizes, Point.CREATOR);
50 | }
51 |
52 | /**
53 | * Creates a new CameraInfo object.
54 | *
55 | * @param description the camera description
56 | * @param cameraId the camera id
57 | * @param sizes the preview resolutions supported by the camera.
58 | */
59 | public CameraInfo(String description, int cameraId, List sizes) {
60 | mDescription = description;
61 | mCameraId = cameraId;
62 | mSupportedPreviewSizes = sizes != null ? new ArrayList<>(sizes) : null;
63 | }
64 |
65 | /**
66 | * @return the camera description
67 | */
68 | public String getDescription() {
69 | return mDescription;
70 | }
71 |
72 | /**
73 | * @return the camera ID
74 | */
75 | public int getCameraId() {
76 | return mCameraId;
77 | }
78 |
79 | /**
80 | * @return the list of supported preview sizes
81 | */
82 | public List getSupportedPreviewSizes() {
83 | return mSupportedPreviewSizes;
84 | }
85 |
86 | public static final Creator CREATOR = new Creator() {
87 | @Override
88 | public CameraInfo createFromParcel(Parcel in) {
89 | return new CameraInfo(in);
90 | }
91 |
92 | @Override
93 | public CameraInfo[] newArray(int size) {
94 | return new CameraInfo[size];
95 | }
96 | };
97 |
98 | @Override
99 | public int describeContents() {
100 | return 0;
101 | }
102 |
103 | @Override
104 | public void writeToParcel(Parcel dest, int flags) {
105 | dest.writeString(mDescription);
106 | dest.writeInt(mCameraId);
107 | dest.writeTypedList(mSupportedPreviewSizes);
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/TCPAudioPacketizer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network;
23 |
24 | import org.jetbrains.annotations.NotNull;
25 |
26 | import java.io.IOException;
27 |
28 | /**
29 | * Defines the RTP packetizer to stream AAC audio over a TCP channel.
30 | * It implements RTP/RTCP over RTSP as defined in RFC 2326, session 10.12.
31 | * Stream data such as RTP packets is encapsulated by an ASCII dollar
32 | * sign (24 hexadecimal), followed by a one-byte channel identifier,
33 | * followed by the length of the encapsulated binary data as a binary,
34 | * two-byte integer in network byte order. The stream data follows
35 | * immediately afterwards, without a CRLF, but including the upper-layer
36 | * protocol headers. Each $ block contains exactly one upper-layer
37 | * protocol data unit, e.g., one RTP packet.
38 | */
39 | public class TCPAudioPacketizer extends RTPAudioPacketizer {
40 |
41 | private static final int RTP_PACKET_SIZE = 2000;
42 |
43 | private final byte[] mPacket; // The RTP packet
44 | private final int mRTPChannel; // The channel to use to send RTP packets
45 | private final int mRTCPChannel; // The channel to use to send RTCP packets
46 |
47 | /**
48 | * Creates a new TCPAudioPacketizer object.
49 | *
50 | * @param connection the StreamConnection that owns the packetizer
51 | * @param rtpChannel the channel used to send RTP packets
52 | * @param rtcpChannel the channel used to send RTCP packets
53 | * @param clock the clock rate in Hz
54 | * @param seq the sequence number of the first packet
55 | */
56 | public TCPAudioPacketizer(@NotNull StreamConnection connection,
57 | int rtpChannel, int rtcpChannel,
58 | int clock, int seq) {
59 | super(connection, clock, RTP_PACKET_SIZE, seq);
60 | mPacket = new byte[4 + RTP_PACKET_SIZE];
61 | mRTPChannel = rtpChannel;
62 | mRTCPChannel = rtcpChannel;
63 | mPacket[0] = '$';
64 | }
65 |
66 | @Override
67 | protected void rtpSend(byte[] data, int length) throws IOException {
68 | mPacket[1] = (byte) mRTPChannel;
69 | mPacket[2] = (byte) (length >> 8);
70 | mPacket[3] = (byte) length;
71 | System.arraycopy(data, 0, mPacket, 4, length);
72 | mConnection.write(mPacket, 0, 4 + length);
73 | }
74 |
75 | @Override
76 | protected void rtcpSend(byte[] data, int length) throws IOException {
77 | mPacket[1] = (byte) (mRTCPChannel);
78 | mPacket[2] = (byte) (length >> 8);
79 | mPacket[3] = (byte) length;
80 | System.arraycopy(data, 0, mPacket, 4, length);
81 | mConnection.write(mPacket, 0, 4 + length);
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/TCPVideoPacketizer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network;
23 |
24 | import org.jetbrains.annotations.NotNull;
25 |
26 | import java.io.IOException;
27 |
28 | /**
29 | * Defines the RTP packetizer to stream AVC video slices over a TCP channel.
30 | * It implements RTP/RTCP over RTSP as defined in RFC 2326, session 10.12.
31 | * Stream data such as RTP packets is encapsulated by an ASCII dollar
32 | * sign (24 hexadecimal), followed by a one-byte channel identifier,
33 | * followed by the length of the encapsulated binary data as a binary,
34 | * two-byte integer in network byte order. The stream data follows
35 | * immediately afterwards, without a CRLF, but including the upper-layer
36 | * protocol headers. Each $ block contains exactly one upper-layer
37 | * protocol data unit, e.g., one RTP packet.
38 | */
39 | public class TCPVideoPacketizer extends RTPVideoPacketizer {
40 |
41 | private static final int RTP_PACKET_SIZE = 65000;
42 |
43 | private final byte[] mPacket; // The RTP packet
44 | private final int mRTPChannel; // The channel to use to send RTP packets
45 | private final int mRTCPChannel; // The channel to use to send RTCP packets
46 |
47 | /**
48 | * Creates a new TCPVideoPacketizer object.
49 | *
50 | * @param connection the StreamConnection that owns the packetizer
51 | * @param rtpChannel the channel used to send RTP packets
52 | * @param rtcpChannel the channel used to send RTCP packets
53 | * @param clock the clock rate in Hz
54 | * @param seq the sequence number of the first packet
55 | */
56 | public TCPVideoPacketizer(@NotNull StreamConnection connection,
57 | int rtpChannel, int rtcpChannel,
58 | int clock, int seq) {
59 | super(connection, clock, RTP_PACKET_SIZE, seq);
60 | mPacket = new byte[4 + RTP_PACKET_SIZE];
61 | mRTPChannel = rtpChannel;
62 | mRTCPChannel = rtcpChannel;
63 | mPacket[0] = '$';
64 | }
65 |
66 | @Override
67 | protected void rtpSend(byte[] data, int length) throws IOException {
68 | mPacket[1] = (byte) mRTPChannel;
69 | mPacket[2] = (byte) (length >> 8);
70 | mPacket[3] = (byte) length;
71 | System.arraycopy(data, 0, mPacket, 4, length);
72 | mConnection.write(mPacket, 0, 4 + length);
73 | }
74 |
75 | @Override
76 | protected void rtcpSend(byte[] data, int length) throws IOException {
77 | mPacket[1] = (byte) (mRTCPChannel);
78 | mPacket[2] = (byte) (length >> 8);
79 | mPacket[3] = (byte) length;
80 | System.arraycopy(data, 0, mPacket, 4, length);
81 | mConnection.write(mPacket, 0, 4 + length);
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/Mangocam/API/DisconnectCommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.Mangocam.API;
23 |
24 | import android.content.Context;
25 | import android.util.JsonReader;
26 |
27 | import org.jetbrains.annotations.NotNull;
28 | import org.json.JSONException;
29 |
30 | import java.io.IOException;
31 | import java.io.StringReader;
32 | import java.util.Random;
33 |
34 | /**
35 | * Defines the Mangocam API DISCONNECT command.
36 | */
37 | public class DisconnectCommand implements MangocamCommand {
38 |
39 | private final Context mContext;
40 | private int mWaitSec = 0, mWaitSecMin = 0, mWaitSecMax = 0;
41 | private String mWaitReason = "";
42 |
43 | /**
44 | * Creates a new DisconnectCommand object.
45 | *
46 | * @param context the context where the object is used
47 | */
48 | public DisconnectCommand(@NotNull Context context) {
49 | mContext = context;
50 | }
51 |
52 | @Override
53 | public String get() throws JSONException {
54 | return "OK {\"cmd\":\"DISCONNECT\"}\r\n";
55 | }
56 |
57 | @Override
58 | public void parse(String command) throws IOException {
59 | if (!command.startsWith("DISCONNECT "))
60 | throw new IllegalArgumentException("wrong command");
61 | command = command.substring(11);
62 | JsonReader jr = new JsonReader(new StringReader(command));
63 | jr.beginObject();
64 | while (jr.hasNext()) {
65 | switch (jr.nextName()) {
66 | case "wait_time_secs":
67 | mWaitSec = jr.nextInt();
68 | break;
69 | case "wait_time_secs_min":
70 | mWaitSecMin = jr.nextInt();
71 | break;
72 | case "wait_time_secs_max":
73 | mWaitSecMax = jr.nextInt();
74 | break;
75 | case "wait_reason":
76 | mWaitReason = jr.nextString();
77 | break;
78 | default:
79 | jr.skipValue();
80 | }
81 | }
82 | jr.endObject();
83 | }
84 |
85 | /**
86 | * @return the requested wait delay in seconds before to reconnect
87 | */
88 | public int getWaitDelay() {
89 | if (mWaitSecMax > mWaitSecMin) {
90 | Random random = new Random(System.currentTimeMillis());
91 | return mWaitSecMin + random.nextInt(mWaitSecMax - mWaitSecMin);
92 | } else {
93 | return mWaitSec;
94 | }
95 | }
96 |
97 | /**
98 | * @return the reason to wait before to reconnect
99 | */
100 | public String getWaitReason() {
101 | return mWaitReason;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/DDNS/DuckDNSClient.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.DDNS;
23 |
24 | import android.content.Context;
25 | import android.util.Log;
26 |
27 | import com.spynet.camera.ui.SettingsActivity;
28 |
29 | import org.jetbrains.annotations.NotNull;
30 |
31 | import java.io.BufferedReader;
32 | import java.io.FileNotFoundException;
33 | import java.io.InputStream;
34 | import java.io.InputStreamReader;
35 | import java.net.HttpURLConnection;
36 | import java.net.URL;
37 | import java.text.DateFormat;
38 | import java.util.Date;
39 |
40 | /**
41 | * Implements the Duck DNS client (https://www.duckdns.org).
42 | */
43 | public class DuckDNSClient extends DDNSClient {
44 |
45 | protected String mToken; // The account token (aka password)
46 |
47 | /**
48 | * Creates a new DuckDNSClient object.
49 | *
50 | * @param context the context where the NoIpClient is used
51 | * @param hostname the public hostname handled by the DDNS service
52 | * @param username the DDNS service username
53 | * @param password the DDNS service password
54 | */
55 | public DuckDNSClient(@NotNull Context context, String hostname, String username, String password) {
56 | super(context, hostname, username, password);
57 | mToken = password;
58 | mURL = "https://www.duckdns.org/update";
59 | }
60 |
61 | @Override
62 | protected String updateDDNS() {
63 | HttpURLConnection connection = null;
64 | try {
65 | URL url = new URL(mURL + "?" + "domains=" + mHostname + "&token=" + mToken + "&verbose=true");
66 | connection = (HttpURLConnection) url.openConnection();
67 | connection.addRequestProperty("User-Agent", mUserAgent);
68 | connection.setConnectTimeout(TIMEOUT);
69 | connection.setReadTimeout(TIMEOUT);
70 | InputStream in;
71 | try {
72 | in = connection.getInputStream();
73 | } catch (FileNotFoundException e) {
74 | in = connection.getErrorStream();
75 | }
76 | BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
77 | String result = "", data;
78 | while ((data = reader.readLine()) != null) result += data + " ";
79 | Log.v(TAG, "DDNS update result: " + result);
80 | return result;
81 | } catch (Exception e) {
82 | Log.e(TAG, "DDNS update request failed", e);
83 | return null;
84 | } finally {
85 | if (connection != null)
86 | connection.disconnect();
87 | }
88 | }
89 |
90 | @Override
91 | protected void parseResult(String result) {
92 | String currentDateTimeString = DateFormat.getDateTimeInstance().format(new Date());
93 | SettingsActivity.setServerDDNSLastUpdate(mContext, currentDateTimeString + " - " + result);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/Angelcam/API/HungUpMessage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.Angelcam.API;
23 |
24 | import java.io.ByteArrayOutputStream;
25 | import java.io.IOException;
26 | import java.io.InvalidObjectException;
27 |
28 | /**
29 | * Defines the Arrow protocol HUP message.
30 | * Hangup notification. It might be sent by both client and server to notify the other side of the
31 | * communication that a session with a given ID has been terminated.
32 | */
33 | public class HungUpMessage extends ControlMessage {
34 |
35 | private final int mSessionID; // Session ID identifying a connection to a local service
36 | private final int mErrorCode; // Error code
37 |
38 | /**
39 | * Creates a new HungUpMessage object.
40 | *
41 | * @param messageID message ID, used for request/response pairing
42 | * @param sessionID ID of the session that has been terminated
43 | * @param errorCode error code
44 | */
45 | public HungUpMessage(int messageID, int sessionID, int errorCode) {
46 | super(messageID, TYPE_HUP);
47 | mSessionID = sessionID;
48 | mErrorCode = errorCode;
49 | }
50 |
51 | /**
52 | * Wraps an HungUpMessage object around a ControlMessage object.
53 | *
54 | * @param message the original ControlMessage object
55 | * @throws InvalidObjectException if the {@code message} doesn't match
56 | */
57 | public HungUpMessage(ControlMessage message) throws InvalidObjectException {
58 | super(message.mMessageID, message.mType);
59 | if (mType != TYPE_HUP)
60 | throw new InvalidObjectException("the message is not an HUP message");
61 | if (message.mData == null)
62 | throw new InvalidObjectException("the message has no data");
63 | if (message.mData.length != 8)
64 | throw new InvalidObjectException("the message contains invalid data");
65 | mSessionID = ((message.mData[1] & 0xff) << 16) |
66 | ((message.mData[2] & 0xff) << 8) | (message.mData[3] & 0xff);
67 | mErrorCode = ((message.mData[4] & 0xff) << 24) | ((message.mData[5] & 0xff) << 16) |
68 | ((message.mData[6] & 0xff) << 8) | (message.mData[7] & 0xff);
69 | }
70 |
71 | @Override
72 | public byte[] toByteArray() throws IOException {
73 |
74 | ByteArrayOutputStream buffer = new ByteArrayOutputStream();
75 |
76 | // error_code - 32bit unsigned integer
77 | buffer.write(mErrorCode >> 24);
78 | buffer.write(mErrorCode >> 16);
79 | buffer.write(mErrorCode >> 8);
80 | buffer.write(mErrorCode);
81 |
82 | mData = buffer.toByteArray();
83 | return super.toByteArray();
84 | }
85 |
86 | @Override
87 | public int getSessionID() {
88 | return mSessionID;
89 | }
90 |
91 | /**
92 | * @return the error code
93 | */
94 | public int getErrorCode() {
95 | return mErrorCode;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/app/src/main/aidl/com/spynet/camera/services/IStreamService.aidl:
--------------------------------------------------------------------------------
1 | package com.spynet.camera.services;
2 |
3 | import com.spynet.camera.media.CameraInfo;
4 | import com.spynet.camera.services.IStreamServiceCallBack;
5 |
6 | /**
7 | * Interface defining the methods to communicate with the StreamService.
8 | */
9 | interface IStreamService {
10 | /**
11 | * Registers the callback used by the StreamService to communicate with the client.
12 | */
13 | oneway void registerCallBack(in IStreamServiceCallBack cb);
14 |
15 | /**
16 | * Restarts a service functionality.
17 | *
18 | * @param what what to restart
19 | */
20 | void restart(in String what);
21 |
22 | /**
23 | * @return the number of available cameras
24 | */
25 | int getNumberOfCameras();
26 |
27 | /**
28 | * Returns the information of one camera.
29 | *
30 | * @param index the index of the information to be returned,
31 | * from 0 to {@code getNumberOfCameras()} - 1
32 | * @return the information of the camera referred by {@code cameraId}
33 | */
34 | CameraInfo getCameraInfo(int index);
35 |
36 | /**
37 | * Sets the surface where to stream the video.
38 | *
39 | * @param surface the surface where to stream the video, null to render offscreen
40 | */
41 | void setSurface(in Surface surface);
42 |
43 | /**
44 | * @return whether the screen capture camera is used
45 | */
46 | boolean isScreenCaptureCamera();
47 |
48 | /**
49 | * @return whether a front camera is used
50 | */
51 | boolean isFrontCamera();
52 |
53 | /**
54 | * @return the frame size in pixels
55 | */
56 | Point getFrameSize();
57 |
58 | /**
59 | * @return the average frame rate in frames per second
60 | */
61 | float getAverageFrameRate();
62 |
63 | /**
64 | * Sets the camera zoom.
65 | *
66 | * @param zoom the zoom factor
67 | */
68 | void setZoom(float zoom);
69 |
70 | /**
71 | * @return the camera zoom
72 | */
73 | float getZoom();
74 |
75 | /**
76 | * Starts camera auto-focus.
77 | *
78 | * @param x the horizontal coordinate of the focus area, in the range -1000 to 1000.
79 | * @param y the vertical coordinate of the focus area, in the range -1000 to 1000.
80 | */
81 | void autoFocus(int x, int y);
82 |
83 | /**
84 | * @return the video bitrate in bps
85 | */
86 | int getVideoBitrate();
87 |
88 | /**
89 | * @return the audio bitrate in bps
90 | */
91 | int getAudioBitrate();
92 |
93 | /**
94 | * @return the number of active streams
95 | */
96 | int getNumberOfStreams();
97 |
98 | /**
99 | * @return the number of active audio streams
100 | */
101 | int getNumberOfAudioStreams();
102 |
103 | /**
104 | * Sets the audio gain.
105 | *
106 | * @param audio gain in dB
107 | */
108 | void setGain(double gain);
109 |
110 | /**
111 | * Sets the audio mute state.
112 | *
113 | * @param muet the mute state
114 | */
115 | void setMute(boolean mute);
116 |
117 | /**
118 | * @return the audio mute state
119 | */
120 | boolean getMute();
121 |
122 | /**
123 | * @return whether the H264 stream is available
124 | */
125 | boolean isH264Available();
126 |
127 | /**
128 | * @return whether the MJPEG stream is available
129 | */
130 | boolean isMJPEGAvailable();
131 |
132 | /**
133 | * @return whether the screen capture is available
134 | */
135 | boolean isScreenCaptureAvailable();
136 |
137 | /**
138 | * @return whether the MangocamAdapter is connected
139 | */
140 | boolean isMangocamConnected();
141 |
142 | /**
143 | * @return whether the AngelcamAdapter is connected
144 | */
145 | boolean isAngelcamConnected();
146 | }
147 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/media/AudioData.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.media;
23 |
24 | import android.media.AudioFormat;
25 |
26 | /**
27 | * Defines a buffer containing audio data.
28 | */
29 | public class AudioData {
30 |
31 | private static final int FORMAT_COMPRESSED = -1;
32 | private static final int TYPE_UNCOMPRESSED_AUDIO = 1;
33 | private static final int TYPE_COMPRESSED_AUDIO = 2;
34 | private static final int TYPE_AUDIO_CONFIG = 3;
35 |
36 | private final byte[] data; // The audio data
37 | private final int format; // The data format
38 | private final int type; // The data type
39 | private final long timestamp; // The timestamp
40 |
41 | /**
42 | * Creates a new AudioData object that contains uncompressed audio.
43 | *
44 | * @param data the raw data
45 | * @param format the data format ({@link AudioFormat})
46 | * @param timestamp the timestamp
47 | */
48 | public AudioData(byte[] data, int format, long timestamp) {
49 | this.data = (data != null ? data.clone() : null);
50 | this.format = format;
51 | this.timestamp = timestamp;
52 | this.type = TYPE_UNCOMPRESSED_AUDIO;
53 | }
54 |
55 | /**
56 | * Creates a new AudioData object that contains compressed audio.
57 | *
58 | * @param data the raw data
59 | * @param timestamp the timestamp
60 | */
61 | public AudioData(byte[] data, long timestamp) {
62 | this.data = (data != null ? data.clone() : null);
63 | this.format = FORMAT_COMPRESSED;
64 | this.timestamp = timestamp;
65 | this.type = TYPE_COMPRESSED_AUDIO;
66 | }
67 |
68 | /**
69 | * Creates a new AudioData object that contains audio configuration information.
70 | *
71 | * @param data the raw data
72 | */
73 | public AudioData(byte[] data) {
74 | this.data = (data != null ? data.clone() : null);
75 | this.format = FORMAT_COMPRESSED;
76 | this.timestamp = 0;
77 | this.type = TYPE_AUDIO_CONFIG;
78 | }
79 |
80 | /**
81 | * @return the raw data
82 | */
83 | public byte[] getData() {
84 | return data;
85 | }
86 |
87 | /**
88 | * @return the data format ({@link AudioFormat})
89 | */
90 | public int getFormat() {
91 | return format;
92 | }
93 |
94 | /**
95 | * @return the timestamp
96 | */
97 | public long getTimestamp() {
98 | return timestamp;
99 | }
100 |
101 | /**
102 | * @return {@code true} if the data represents compressed audio,
103 | * {@code false} otherwise
104 | */
105 | public boolean isCompressed() {
106 | return format == FORMAT_COMPRESSED;
107 | }
108 |
109 | /**
110 | * @return {@code true} if the data contains audio configuration information,
111 | * {@code false} otherwise
112 | */
113 | public boolean isConfig() {
114 | return type == TYPE_AUDIO_CONFIG;
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/.idea/markdown-navigator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/UDPAudioPacketizer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network;
23 |
24 | import org.jetbrains.annotations.NotNull;
25 |
26 | import java.io.IOException;
27 | import java.net.DatagramPacket;
28 | import java.net.DatagramSocket;
29 | import java.net.InetAddress;
30 | import java.net.SocketException;
31 |
32 | /**
33 | * Defines the RTP packetizer to stream AAC audio using the UDP protocol.
34 | */
35 | public class UDPAudioPacketizer extends RTPAudioPacketizer {
36 |
37 | protected static final int RTP_PACKET_SIZE = 1400;
38 |
39 | private final DatagramSocket mRTPSocket; // The socket to send RTP packets to
40 | private final DatagramSocket mRTCPSocket; // The socket to send RTCP packets to
41 | private final DatagramPacket mPacket; // The UDP packet to send
42 | private final int mRTPPort; // The client port used by the RTP protocol
43 | private final int mRTCPPort; // The client port used by the RTCP protocol
44 |
45 | /**
46 | * Creates a new UDPAudioPacketizer object.
47 | *
48 | * @param connection the StreamConnection that owns the packetizer
49 | * @param host the host to send packets to
50 | * @param rtpPort the UDP port to send RTP packets to
51 | * @param rtcpPort the UDP port to send RTCP packets to
52 | * @param clock the clock rate in Hz
53 | * @param seq the sequence number of the first packet
54 | */
55 | public UDPAudioPacketizer(@NotNull StreamConnection connection,
56 | InetAddress host, int rtpPort, int rtcpPort,
57 | int clock, int seq)
58 | throws SocketException {
59 | super(connection, clock, RTP_PACKET_SIZE, seq);
60 | mRTPSocket = new DatagramSocket();
61 | mRTCPSocket = new DatagramSocket(mRTPSocket.getLocalPort() + 1);
62 | mPacket = new DatagramPacket(new byte[RTP_PACKET_SIZE], RTP_PACKET_SIZE);
63 | mPacket.setAddress(host);
64 | mRTPPort = rtpPort;
65 | mRTCPPort = rtcpPort;
66 | }
67 |
68 | @Override
69 | protected void rtpSend(byte[] data, int length) throws IOException {
70 | mPacket.setData(data, 0, length);
71 | mPacket.setPort(mRTPPort);
72 | mRTPSocket.send(mPacket);
73 | }
74 |
75 | @Override
76 | protected void rtcpSend(byte[] data, int length) throws IOException {
77 | mPacket.setData(data, 0, length);
78 | mPacket.setPort(mRTCPPort);
79 | mRTCPSocket.send(mPacket);
80 | }
81 |
82 | @Override
83 | public void close() {
84 | super.close();
85 | mRTPSocket.close();
86 | mRTCPSocket.close();
87 | }
88 |
89 | /**
90 | * @return the local port used by the RTP protocol
91 | */
92 | public int getRTPLocalPort() {
93 | return mRTPSocket.getLocalPort();
94 | }
95 |
96 | /**
97 | * @return the local port used by the RTCP protocol
98 | */
99 | public int getRTCPLocalPort() {
100 | return mRTCPSocket.getLocalPort();
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/UDPVideoPacketizer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network;
23 |
24 | import org.jetbrains.annotations.NotNull;
25 |
26 | import java.io.IOException;
27 | import java.net.DatagramPacket;
28 | import java.net.DatagramSocket;
29 | import java.net.InetAddress;
30 | import java.net.SocketException;
31 |
32 | /**
33 | * Defines the RTP packetizer to stream AVC video slices using the UDP protocol.
34 | */
35 | public class UDPVideoPacketizer extends RTPVideoPacketizer {
36 |
37 | protected static final int RTP_PACKET_SIZE = 1400;
38 |
39 | private final DatagramSocket mRTPSocket; // The socket to send RTP packets to
40 | private final DatagramSocket mRTCPSocket; // The socket to send RTCP packets to
41 | private final DatagramPacket mPacket; // The UDP packet to send
42 | private final int mRTPPort; // The client port used by the RTP protocol
43 | private final int mRTCPPort; // The client port used by the RTCP protocol
44 |
45 | /**
46 | * Creates a new UDPVideoPacketizer object.
47 | *
48 | * @param connection the StreamConnection that owns the packetizer
49 | * @param host the host to send packets to
50 | * @param rtpPort the UDP port to send RTP packets to
51 | * @param rtcpPort the UDP port to send RTCP packets to
52 | * @param clock the clock rate in Hz
53 | * @param seq the sequence number of the first packet
54 | */
55 | public UDPVideoPacketizer(@NotNull StreamConnection connection,
56 | InetAddress host, int rtpPort, int rtcpPort,
57 | int clock, int seq)
58 | throws SocketException {
59 | super(connection, clock, RTP_PACKET_SIZE, seq);
60 | mRTPSocket = new DatagramSocket();
61 | mRTCPSocket = new DatagramSocket(mRTPSocket.getLocalPort() + 1);
62 | mPacket = new DatagramPacket(new byte[RTP_PACKET_SIZE], RTP_PACKET_SIZE);
63 | mPacket.setAddress(host);
64 | mRTPPort = rtpPort;
65 | mRTCPPort = rtcpPort;
66 | }
67 |
68 | @Override
69 | protected void rtpSend(byte[] data, int length) throws IOException {
70 | mPacket.setData(data, 0, length);
71 | mPacket.setPort(mRTPPort);
72 | mRTPSocket.send(mPacket);
73 | }
74 |
75 | @Override
76 | protected void rtcpSend(byte[] data, int length) throws IOException {
77 | mPacket.setData(data, 0, length);
78 | mPacket.setPort(mRTCPPort);
79 | mRTCPSocket.send(mPacket);
80 | }
81 |
82 | @Override
83 | public void close() {
84 | super.close();
85 | mRTPSocket.close();
86 | mRTCPSocket.close();
87 | }
88 |
89 | /**
90 | * @return the local port used by the RTP protocol
91 | */
92 | public int getRTPLocalPort() {
93 | return mRTPSocket.getLocalPort();
94 | }
95 |
96 | /**
97 | * @return the local port used by the RTCP protocol
98 | */
99 | public int getRTCPLocalPort() {
100 | return mRTCPSocket.getLocalPort();
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/common/Image.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.common;
23 |
24 | import android.graphics.Rect;
25 | import android.graphics.YuvImage;
26 |
27 | import java.io.OutputStream;
28 |
29 | /**
30 | * Common utilities to handle images.
31 | */
32 | public final class Image {
33 |
34 | /**
35 | * Hidden constructor, the class cannot be instantiated.
36 | */
37 | private Image() {
38 | }
39 |
40 | /**
41 | * Converts a NV12 image to a YUV420SemiPlanar image.
42 | * We assume that there's no padding (stride = {@code width}) and that the {@code data}
43 | * buffer contains exactly one image, i.e. its size equals {@code width * height * 3 / 2}.
44 | *
45 | * @param data the image data
46 | * @param width the image width
47 | * @param height the image height
48 | */
49 | public static void convertNV12ToYUV420SemiPlanar(byte[] data, int width, int height) {
50 | for (int i = width * height; i < data.length; ) {
51 | byte tmp = data[i];
52 | data[i] = data[++i];
53 | data[i++] = tmp;
54 | }
55 | }
56 |
57 | /**
58 | * Converts a NV12 image to a YUV420Planar image.
59 | * We assume that there's no padding (stride = {@code width}) and that the {@code data}
60 | * buffer contains exactly one image, i.e. its size equals {@code width * height * 3 / 2}.
61 | *
62 | * @param data the image data
63 | * @param width the image width
64 | * @param height the image height
65 | */
66 | public static void convertNV12ToYUV420Planar(byte[] data, int width, int height) {
67 |
68 | final int c_stride = width / 2;
69 | final int c_size = c_stride * height / 2;
70 | final int cr_offset = width * height;
71 |
72 | byte[] tmp = new byte[c_size * 2];
73 | for (int src = cr_offset, cr_dst = 0, cb_dst = c_size; src < data.length; src++) {
74 | if (src % 2 == 0) {
75 | tmp[cb_dst++] = data[src];
76 | } else {
77 | tmp[cr_dst++] = data[src];
78 | }
79 | }
80 | System.arraycopy(tmp, 0, data, cr_offset, c_size * 2);
81 | }
82 |
83 | /**
84 | * Compress an YUV image to a JPEG image.
85 | * Only ImageFormat.NV21 and ImageFormat.YUY2 are supported for now.
86 | *
87 | * @param data the YUV data
88 | * @param width the width of the image
89 | * @param height the height of the image
90 | * @param format the YUV data format as defined in ImageFormat
91 | * @param quality hint to the compressor, 0-100.
92 | * 0 meaning compress for small size, 100 meaning compress for max quality.
93 | * @param out OutputStream to write the compressed data.
94 | */
95 | public static void compressToJpeg(byte[] data, int width, int height, int format,
96 | int quality, OutputStream out) {
97 | YuvImage img = new YuvImage(data, format, width, height, null);
98 | img.compressToJpeg(new Rect(0, 0, width - 1, height - 1), quality, out);
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/Angelcam/API/AckMessage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.Angelcam.API;
23 |
24 | import java.io.ByteArrayOutputStream;
25 | import java.io.IOException;
26 | import java.io.InvalidObjectException;
27 |
28 | /**
29 | * Defines the Arrow protocol ACK message.
30 | * The message is a response to another Control Protocol message.
31 | * It might be sent by both client and server.
32 | * The message consists of 32bit unsigned integer used as an error code.
33 | */
34 | public class AckMessage extends ControlMessage {
35 |
36 | // OK
37 | public final static int ERROR_NO_ERROR = 0x00000000;
38 | // Unsupported version of the Arrow protocol
39 | public final static int ERROR_UNSUPPORTED_PROTOCOL_VERSION = 0x00000001;
40 | // Access denied (client is not registered)
41 | public final static int ERROR_UNAUTHORIZED = 0x00000002;
42 | // Cannot connect to a given service
43 | public final static int ERROR_CONNECTION_ERROR = 0x00000003;
44 | // unsupported method
45 | public final static int ERROR_UNSUPPORTED_METHOD = 0x00000004;
46 | // internal server error
47 | public final static int ERROR_INTERNAL_SERVER_ERROR = 0xffffffff;
48 |
49 | private final int mErrorCode; // Error code
50 |
51 | /**
52 | * Creates a new AckMessage object.
53 | *
54 | * @param messageID message ID, used for request/response pairing
55 | * @param errorCode error code
56 | */
57 | public AckMessage(int messageID, int errorCode) {
58 | super(messageID, TYPE_ACK);
59 | mErrorCode = errorCode;
60 | }
61 |
62 | /**
63 | * Wraps an AckMessage object around a ControlMessage object.
64 | *
65 | * @param message the original ControlMessage object
66 | * @throws InvalidObjectException if the {@code message} doesn't match
67 | */
68 | public AckMessage(ControlMessage message) throws InvalidObjectException {
69 | super(message.mMessageID, message.mType);
70 | if (mType != TYPE_ACK)
71 | throw new InvalidObjectException("the message is not an ACK message");
72 | if (message.mData == null)
73 | throw new InvalidObjectException("the message has no data");
74 | if (message.mData.length != 4)
75 | throw new InvalidObjectException("the message contains invalid data");
76 | mErrorCode = ((message.mData[0] & 0xff) << 24) | ((message.mData[1] & 0xff) << 16) |
77 | ((message.mData[2] & 0xff) << 8) | (message.mData[3] & 0xff);
78 | }
79 |
80 | @Override
81 | public byte[] toByteArray() throws IOException {
82 |
83 | ByteArrayOutputStream buffer = new ByteArrayOutputStream();
84 |
85 | // error_code - 32bit unsigned integer
86 | buffer.write(mErrorCode >> 24);
87 | buffer.write(mErrorCode >> 16);
88 | buffer.write(mErrorCode >> 8);
89 | buffer.write(mErrorCode);
90 |
91 | mData = buffer.toByteArray();
92 | return super.toByteArray();
93 | }
94 |
95 | /**
96 | * @return the error code
97 | */
98 | public int getErrorCode() {
99 | return mErrorCode;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/Mangocam/API/ResetCommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network.Mangocam.API;
23 |
24 | import android.content.Context;
25 | import android.util.JsonReader;
26 |
27 | import org.jetbrains.annotations.NotNull;
28 | import org.json.JSONException;
29 |
30 | import java.io.IOException;
31 | import java.io.StringReader;
32 |
33 | /**
34 | * Defines the Mangocam API RESET command.
35 | */
36 | public class ResetCommand implements MangocamCommand {
37 |
38 | private final Context mContext;
39 | private String mErrorMessage = "";
40 | private int mErrorCode = 0;
41 |
42 | /**
43 | * Creates a new ResetCommand object.
44 | *
45 | * @param context the context where the object is used
46 | */
47 | public ResetCommand(@NotNull Context context) {
48 | mContext = context;
49 | }
50 |
51 | @Override
52 | public String get() throws JSONException {
53 | return "RESET\r\n";
54 | }
55 |
56 | @Override
57 | public void parse(String command) throws IOException, IllegalStateException {
58 | if (command.startsWith("OK ")) {
59 | String json = command.substring(3);
60 | JsonReader jr = new JsonReader(new StringReader(json));
61 | jr.beginObject();
62 | while (jr.hasNext()) {
63 | switch (jr.nextName()) {
64 | case "cmd":
65 | String cmd = jr.nextString();
66 | if (!cmd.equals("RESET"))
67 | throw new IllegalStateException("wrong cmd field");
68 | break;
69 | default:
70 | jr.skipValue();
71 | }
72 | }
73 | jr.endObject();
74 | } else if (command.startsWith("ERR ")) {
75 | String json = command.substring(4);
76 | JsonReader jr = new JsonReader(new StringReader(json));
77 | jr.beginObject();
78 | while (jr.hasNext()) {
79 | switch (jr.nextName()) {
80 | case "cmd":
81 | String cmd = jr.nextString();
82 | if (!cmd.equals("RESET"))
83 | throw new IllegalStateException("wrong cmd field");
84 | break;
85 | case "message":
86 | mErrorMessage = jr.nextString();
87 | break;
88 | case "code":
89 | mErrorCode = jr.nextInt();
90 | break;
91 | default:
92 | jr.skipValue();
93 | }
94 | }
95 | jr.endObject();
96 | } else {
97 | throw new IllegalStateException("wrong response");
98 | }
99 | }
100 |
101 | /**
102 | * @return the error message from the negative response
103 | */
104 | public String getErrorMessge() {
105 | return mErrorMessage;
106 | }
107 |
108 | /**
109 | * @return the error code from the negative response
110 | */
111 | public int getErrorCode() {
112 | return mErrorCode;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/app/src/main/res/values/array.xml:
--------------------------------------------------------------------------------
1 |
2 |
22 |
23 |
24 |
25 | "64"
26 | "128"
27 | "256"
28 | "384"
29 | "512"
30 | "768"
31 | "1024"
32 | "1536"
33 | "2048"
34 | "3072"
35 | "4096"
36 | "6144"
37 | "8192"
38 |
39 |
40 | "10"
41 | "15"
42 | "20"
43 | "25"
44 | "30"
45 |
46 |
47 | "1"
48 | "2"
49 | "5"
50 | "10"
51 |
52 |
53 | "32"
54 | "64"
55 | "128"
56 | "256"
57 |
58 |
59 | "-6"
60 | "0"
61 | "6"
62 | "12"
63 | "18"
64 | "24"
65 |
66 |
67 | "-6"
68 | "0"
69 | "+6"
70 | "+12"
71 | "+18"
72 | "+24"
73 |
74 |
75 | "25"
76 | "50"
77 | "75"
78 | "100"
79 |
80 |
81 | "1"
82 | "2"
83 | "5"
84 | "10"
85 | "15"
86 | "20"
87 | "25"
88 | "30"
89 |
90 |
91 | "No-IP (www.noip.com)"
92 | "Dynu (www.dynu.com)"
93 | "DNSdynamic (www.dnsdynamic.org)"
94 | "FreeDNS (freedns.afraid.org)"
95 | "Duck DNS (www.duckdns.org/)"
96 |
97 |
98 | "noip"
99 | "dynu"
100 | "dnsdynamic"
101 | "freedns"
102 | "duckdns"
103 |
104 |
105 | "WiFi only"
106 | "Mobile only"
107 | "WiFi and mobile"
108 |
109 |
110 | "wifi"
111 | "mobile"
112 | "all"
113 |
114 |
--------------------------------------------------------------------------------
/app/src/main/java/com/spynet/camera/network/TCPListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of spyNet Camera, the Android IP camera
3 | *
4 | * Copyright (C) 2016-2017 Paolo Dematteis
5 | *
6 | * spyNet Camera is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * spyNet Camera is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * Paolo Dematteis - spynet314@gmail.com
20 | */
21 |
22 | package com.spynet.camera.network;
23 |
24 | import android.util.Log;
25 |
26 | import org.jetbrains.annotations.NotNull;
27 |
28 | import java.io.Closeable;
29 | import java.io.IOException;
30 | import java.net.ServerSocket;
31 | import java.net.Socket;
32 | import java.net.SocketException;
33 |
34 | /**
35 | * Defines a generic TCP listener that runs in its own thread.
36 | */
37 | public class TCPListener implements Closeable {
38 |
39 | protected final String TAG = getClass().getSimpleName();
40 |
41 | private final ServerSocket mSocket; // The listening socket
42 | private final ListenerCallback mCallback; // The callback to notify the client
43 | private final Thread mThread; // The listening thread
44 |
45 | /**
46 | * Defines the interface that the client has to implement to receive notifications
47 | * about incoming connections.
48 | */
49 | public interface ListenerCallback {
50 | /**
51 | * Notifies a new incoming connection.
52 | *
53 | * @param listener the TCPListener that accepted the connection
54 | * @param socket the socket to handle the connection
55 | * @throws IOException if an error occurs while handling the new connection
56 | */
57 | void onNewConnection(TCPListener listener, Socket socket) throws IOException;
58 | }
59 |
60 | /**
61 | * Creates a new TCPListener object.
62 | *
63 | * @param port the server port
64 | * @param callback the callback implemented by the client
65 | * @throws IOException if an error occurs while creating the socket
66 | */
67 | public TCPListener(int port, @NotNull ListenerCallback callback) throws IOException {
68 | mSocket = new ServerSocket(port);
69 | mCallback = callback;
70 | mThread = new Thread(new Runnable() {
71 | @Override
72 | public void run() {
73 | listen();
74 | }
75 | });
76 | mThread.start();
77 | }
78 |
79 | /**
80 | * Closes the listener.
81 | */
82 | @Override
83 | public void close() {
84 | try {
85 | mThread.interrupt();
86 | mSocket.close();
87 | } catch (Exception e) {
88 | Log.e(TAG, "unexpected exception while closing the socket", e);
89 | }
90 | }
91 |
92 | /**
93 | * Listen for incoming connections and notify the client.
94 | */
95 | private void listen() {
96 | Log.d(TAG, "listener started");
97 | try {
98 | while (true) {
99 | try {
100 | Log.v(TAG, "listening for a new connection");
101 | Socket socket = mSocket.accept();
102 | Log.v(TAG, "new connection from " + socket.toString());
103 | mCallback.onNewConnection(this, socket);
104 | } catch (SocketException e) {
105 | Log.v(TAG, "socket closed");
106 | break;
107 | } catch (Exception e) {
108 | Log.e(TAG, "unexpected exception while listening, continue", e);
109 | }
110 | }
111 | } finally {
112 | close();
113 | Log.d(TAG, "listener stopped");
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------