From 1e70fcce830f293a6645a40fe4af7f2089bed785 Mon Sep 17 00:00:00 2001 From: Lamba Date: Mon, 18 Feb 2019 13:10:01 +0100 Subject: [PATCH 01/12] Added Kotlin coroutines wrappers, moved publishing on Jitpack and rewrote the Gradle script in Kotlin. Scaffolding overhaul to match standard Gradle project. --- .gitignore | 4 + .gradle/4.8/fileChanges/last-build.bin | Bin 1 -> 0 bytes .gradle/4.8/fileHashes/fileHashes.bin | Bin 19447 -> 0 bytes .gradle/4.8/fileHashes/fileHashes.lock | Bin 17 -> 0 bytes .gradle/4.8/taskHistory/taskHistory.bin | Bin 19625 -> 0 bytes .gradle/4.8/taskHistory/taskHistory.lock | Bin 17 -> 0 bytes .gradle/vcsWorkingDirs/gc.properties | 0 .idea/libraries/gradle_wrapper.xml | 9 - KOTLIN.md | 47 ++ LICENSE.txt => LICENSE | 0 README.md | 434 +++++++++--------- build.gradle.kts | 28 ++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54413 bytes .../wrapper/gradle-wrapper.properties | 3 +- lib/gradlew => gradlew | 0 lib/gradlew.bat => gradlew.bat | 168 +++---- lib/.gitignore | 174 ------- lib/build.gradle | 150 ------ lib/settings.gradle | 2 - settings.gradle.kts | 11 + .../be/teletask/onvif/DiscoveryManager.java | 0 .../java/be/teletask/onvif/DiscoveryMode.java | 0 .../be/teletask/onvif/DiscoveryThread.java | 0 .../be/teletask/onvif/OnvifDiscovery.java | 0 .../java/be/teletask/onvif/OnvifExecutor.java | 0 .../java/be/teletask/onvif/OnvifManager.java | 0 .../java/be/teletask/onvif/OnvifUtils.java | 0 .../be/teletask/onvif/OnvifXMLBuilder.java | 0 .../onvif/listeners/DiscoveryCallback.java | 0 .../onvif/listeners/DiscoveryListener.java | 0 .../OnvifDeviceInformationListener.java | 0 .../listeners/OnvifMediaProfilesListener.java | 0 .../OnvifMediaStreamURIListener.java | 0 .../listeners/OnvifResponseListener.java | 0 .../listeners/OnvifServicesListener.java | 0 .../java/be/teletask/onvif/models/Device.java | 0 .../be/teletask/onvif/models/DeviceType.java | 0 .../onvif/models/DiscoveryPacket.java | 0 .../teletask/onvif/models/DiscoveryType.java | 0 .../be/teletask/onvif/models/OnvifDevice.java | 0 .../onvif/models/OnvifDeviceInformation.java | 0 .../onvif/models/OnvifMediaProfile.java | 0 .../be/teletask/onvif/models/OnvifPacket.java | 0 .../teletask/onvif/models/OnvifServices.java | 0 .../be/teletask/onvif/models/OnvifType.java | 0 .../be/teletask/onvif/models/UPnPDevice.java | 0 .../onvif/parsers/DiscoveryParser.java | 0 .../parsers/GetDeviceInformationParser.java | 0 .../onvif/parsers/GetMediaProfilesParser.java | 0 .../onvif/parsers/GetMediaStreamParser.java | 0 .../onvif/parsers/GetServicesParser.java | 0 .../teletask/onvif/parsers/OnvifParser.java | 0 .../be/teletask/onvif/parsers/UPnPParser.java | 0 .../requests/GetDeviceInformationRequest.java | 0 .../requests/GetMediaProfilesRequest.java | 0 .../onvif/requests/GetMediaStreamRequest.java | 0 .../onvif/requests/GetServicesRequest.java | 0 .../teletask/onvif/requests/OnvifRequest.java | 0 .../onvif/responses/OnvifResponse.java | 0 .../onvif/upnp/UPnPDeviceInformation.java | 0 .../upnp/UPnPDeviceInformationListener.java | 0 .../be/teletask/onvif/upnp/UPnPExecutor.java | 0 .../be/teletask/onvif/upnp/UPnPManager.java | 0 .../onvif/upnp/UPnPResponseListener.java | 0 .../teletask/onvif/coroutines/Coroutines.kt | 59 +++ 65 files changed, 452 insertions(+), 637 deletions(-) create mode 100644 .gitignore delete mode 100644 .gradle/4.8/fileChanges/last-build.bin delete mode 100644 .gradle/4.8/fileHashes/fileHashes.bin delete mode 100644 .gradle/4.8/fileHashes/fileHashes.lock delete mode 100644 .gradle/4.8/taskHistory/taskHistory.bin delete mode 100644 .gradle/4.8/taskHistory/taskHistory.lock delete mode 100644 .gradle/vcsWorkingDirs/gc.properties delete mode 100644 .idea/libraries/gradle_wrapper.xml create mode 100644 KOTLIN.md rename LICENSE.txt => LICENSE (100%) create mode 100644 build.gradle.kts create mode 100644 gradle/wrapper/gradle-wrapper.jar rename {lib/gradle => gradle}/wrapper/gradle-wrapper.properties (80%) rename lib/gradlew => gradlew (100%) mode change 100755 => 100644 rename lib/gradlew.bat => gradlew.bat (96%) delete mode 100644 lib/.gitignore delete mode 100644 lib/build.gradle delete mode 100644 lib/settings.gradle create mode 100644 settings.gradle.kts rename {lib/src => src}/main/java/be/teletask/onvif/DiscoveryManager.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/DiscoveryMode.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/DiscoveryThread.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/OnvifDiscovery.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/OnvifExecutor.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/OnvifManager.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/OnvifUtils.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/OnvifXMLBuilder.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/listeners/DiscoveryCallback.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/listeners/DiscoveryListener.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/listeners/OnvifDeviceInformationListener.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/listeners/OnvifMediaProfilesListener.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/listeners/OnvifMediaStreamURIListener.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/listeners/OnvifResponseListener.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/listeners/OnvifServicesListener.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/models/Device.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/models/DeviceType.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/models/DiscoveryPacket.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/models/DiscoveryType.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/models/OnvifDevice.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/models/OnvifDeviceInformation.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/models/OnvifMediaProfile.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/models/OnvifPacket.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/models/OnvifServices.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/models/OnvifType.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/models/UPnPDevice.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/parsers/DiscoveryParser.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/parsers/GetDeviceInformationParser.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/parsers/GetMediaProfilesParser.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/parsers/GetMediaStreamParser.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/parsers/GetServicesParser.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/parsers/OnvifParser.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/parsers/UPnPParser.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/requests/GetDeviceInformationRequest.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/requests/GetMediaProfilesRequest.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/requests/GetMediaStreamRequest.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/requests/GetServicesRequest.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/requests/OnvifRequest.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/responses/OnvifResponse.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/upnp/UPnPDeviceInformation.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/upnp/UPnPDeviceInformationListener.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/upnp/UPnPExecutor.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/upnp/UPnPManager.java (100%) rename {lib/src => src}/main/java/be/teletask/onvif/upnp/UPnPResponseListener.java (100%) create mode 100644 src/main/kotlin/be/teletask/onvif/coroutines/Coroutines.kt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..23e4039 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +out/ +build/ +.gradle/ +.idea/ diff --git a/.gradle/4.8/fileChanges/last-build.bin b/.gradle/4.8/fileChanges/last-build.bin deleted file mode 100644 index f76dd238ade08917e6712764a16a22005a50573d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1 IcmZPo000310RR91 diff --git a/.gradle/4.8/fileHashes/fileHashes.bin b/.gradle/4.8/fileHashes/fileHashes.bin deleted file mode 100644 index b5c324240523935a40234157a2b5e2172bb5248d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19447 zcmeI(T}V?=00;1^M)<>sp$A5miv_LB|q<UQ!?&*Z$wAD{s1( zYU<;+#K>($>ulbs@h zQNPu4ZlBXst*)aD`i?#qm}|<)SC2XK3wun;mZJ;e?=IXBL>mS&M|9w;h$)Skb#M2R z#!R|1H!Rd@){X8lv&cC-<$*6ngl*PycuwyU+4xlZSZu>XzbTpZQ}u?6T}SVZVv$eP SH=+>R_@NWo7<8xp+xQEUFy~JI diff --git a/.gradle/4.8/fileHashes/fileHashes.lock b/.gradle/4.8/fileHashes/fileHashes.lock deleted file mode 100644 index 52dc8428ce3d9afcd2ff315f07ab722e4701e83f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 UcmZSHx?Jq-F|90%}uJ07&MHmDGS4&k9cy0h+Tnw_*=)BMZ+(Sl-_oq4&V>(2DvtXo1v zAr>gs6740Bx)dSUA0qHzo%%xrd$Ud*>K1rQ@Mg2^4zAHb$wS00*g`#^pt_b#%y#$$dx&9qBN!?b84Pd1oi!<-gxc10+giYb;F535W!Ef*2Ub1BLx zQJwfvk-;>RRl+sKwP0ETHYKx~HJD})}ocMfw;^ecpOI?}Q-^-3v5OT|8 zhCSNSDR=Vawj|$LT+zKSyI8rjy!!OP)$_S*rtJ|Sll&K$lX7k|D@=>-qbs?Ab6>JG z^Ty7D_jlJ5Lc}Kq8}t-ZJ&LJ&EQJqqkF)xL0*V}6uU3i*;4z)W&a*u7tFFN?~eTAEm7dr{!}Sk*V%e ztayHS=2WO9&=r)U;b2H^@9hpcvGN1NX{Wk0om)JUKQcX*vUDT46}i?0{6oTQX~J+^ z@iiO^r$&Tz(;}BmTK;lFYYvp$etz0`Ye&!R(iBma5EtT>W%6c8vR~^_U8UTqGCPG- jI+#1JT)n5MHl`;%W4bwAsK|c%i(nIp<93(*Y0-WHbw9r; diff --git a/.gradle/4.8/taskHistory/taskHistory.lock b/.gradle/4.8/taskHistory/taskHistory.lock deleted file mode 100644 index 51a9a473128dcede219860702d9d2892d0eab532..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 UcmZQJo6fer^lyVb0|YPw04+%ax&QzG diff --git a/.gradle/vcsWorkingDirs/gc.properties b/.gradle/vcsWorkingDirs/gc.properties deleted file mode 100644 index e69de29..0000000 diff --git a/.idea/libraries/gradle_wrapper.xml b/.idea/libraries/gradle_wrapper.xml deleted file mode 100644 index 0a9fb73..0000000 --- a/.idea/libraries/gradle_wrapper.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/KOTLIN.md b/KOTLIN.md new file mode 100644 index 0000000..6a44c7a --- /dev/null +++ b/KOTLIN.md @@ -0,0 +1,47 @@ +# ONVIF-Java +--- +[ ![Download](https://api.bintray.com/packages/tomasverhelst/ONVIF-Java/ONVIF-Java/images/download.svg) ](https://bintray.com/tomasverhelst/ONVIF-Java/ONVIF-Java/_latestVersion) + +

+ +

+ +ONVIF is an open industry forum that provides and promotes standardized interfaces for effective interoperability of IP-based physical security products. ONVIF was created to make a standard way of how IP products within CCTV and other security areas can communicate with each other. + +## Kotlin coroutines + +All the Kotlin functions provided are `suspend` functions. All the examples below assumes that you are inside a coroutine context. If not wrap your code inside a `suspend` function or `runBlocking{}`. +I highly recommend to run those functions inside the [`IO`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-i-o.html) dispatcher since the calls are thread blocking. + +### Discovery +Straight forward solution: + +```kotlin +val devices: List = discoverDevices() +``` + +If you need to create and customize a a one-shot `DiscoveryManager`: +```kotlin +val devices = discoverDevices { + discoveryTimeout = 10000 +} +``` + +If using a custom `DiscoveryManager`: +```kotlin + val myDM = DiscoveryManager().apply { discoveryTimeout = 10000 } + val devices = awaitDeviceDiscovery { myDM.discover(it) } +``` + +### Information, Profiles and URIs + +Once you obtained the device host and you know username and password, create the `OnvifDevice` and get its data async using: + +```kotlin +val om = OnvifManager() +val device = OnvifDevice(host, user, pswd) + +val infos = awaitDeviceInformations { om.getDeviceInformation(device, it) } +val profiles = awaitDeviceMediaProfiles { om.getMediaProfiles(device, it) } +val uri = awaitDeviceMediaStramUri { om.getMediaStreamURI(device, profiles.first(), it) } +``` \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE similarity index 100% rename from LICENSE.txt rename to LICENSE diff --git a/README.md b/README.md index 0d05b26..38a0fee 100644 --- a/README.md +++ b/README.md @@ -1,216 +1,218 @@ -# ONVIF-Java ---- -[ ![Download](https://api.bintray.com/packages/tomasverhelst/ONVIF-Java/ONVIF-Java/images/download.svg) ](https://bintray.com/tomasverhelst/ONVIF-Java/ONVIF-Java/_latestVersion) - -

- -

- -ONVIF is an open industry forum that provides and promotes standardized interfaces for effective interoperability of IP-based physical security products. ONVIF was created to make a standard way of how IP products within CCTV and other security areas can communicate with each other. - - -## Features - - - **ONVIF & UPnP discovery** - - ONVIF device management (Services, device information, media profiles, raw media stream uri) - - UPnP device information - - Easily extendable with your own requests - - **Android supported!** - -## Discovery ---- -The OnvifDiscovery class uses the **Web Services Dynamic Discovery (WS-Discovery)**. This is a technical specification that defines a multicast discovery protocol to locate services on a local network. It operates over TCP and UDP port ```3702``` and uses IP multicast address ```239.255.255.250```. As the name suggests, the actual communication between nodes is done using web services standards, notably **SOAP-over-UDP**. - -With WS-Discovery, the discovery tool puts SSDP queries on the network from its unicast address to ```239.255.255.250``` multicast address, sending them to the well-known UDP port 3702. The device receives the query, and answers to the discovery tool's unicast IP address from its unicast IP address. The reply contains information about the Web Services (WS) available on the device. - -**UPnP** works in a very similar way, but on a different UDP port (```1900```). -Compared to the WS-Discovery, the UPnP is intended for a general use (data sharing, communication, entertainment). - -```java -DiscoveryManager manager = new DiscoveryManager(); -manager.setDiscoveryTimeout(10000); -manager.discover(new DiscoveryListener() { - @Override - public void onDiscoveryStarted() { - System.out.println("Discovery started"); - } - - @Override - public void onDevicesFound(List devices) { - for (Device device : devices) - System.out.println("Devices found: " + device.getHostName()); - } -}); -``` - -## ONVIF ---- - -With the ```OnvifManager``` class it is possible to send requests to an ONVIF-supported device. All requests are sent asynchronously and you can use the ```OnvifResponseListener``` for errors and custom response handling. It is possible to create your own ```OnvifDevice``` or retrieve a list from the ```discover``` method in the ```DiscoveryManager``` - -```java -onvifManager = new OnvifManager(); -onvifManager.setOnvifResponseListener(this); -OnvifDevice device = new OnvifDevice("192.168.0.131", "username", "password"); -``` - -### Services -Returns information about services on the device. - -```java -onvifManager.getServices(device, new OnvifServicesListener() { - @Override - public void onServicesReceived(@Nonnull OnvifDevice onvifDevice, OnvifServices services) { - - } -}); -``` - -### Device information -Returns basic device information from the device. This includes the manufacturer, serial number, hardwareId, ... - -```java -onvifManager.getDeviceInformation(device, new OnvifDeviceInformationListener() { - @Override - public void onDeviceInformationReceived(@Nonnull OnvifDevice device, - @Nonnull OnvifDeviceInformation deviceInformation) { - - } -}); -``` - -### Media Profiles -Returns pre-configured or dynamically configured profiles. This command lists all configured profiles in a device. The client does not need to know the media profile in order to use the command. - -```java -onvifManager.getMediaProfiles(device, new OnvifMediaProfilesListener() { - @Override - public void onMediaProfilesReceived(@Nonnull OnvifDevice device, - @Nonnull List mediaProfiles) { - - } -}); -``` - -### Media Stream URI -Returns a raw media stream URI that remains valid indefinitely even if the profile is changed. - -```java -onvifManager.getMediaStreamURI(device, mediaProfiles.get(0), new OnvifMediaStreamURIListener() { - @Override - public void onMediaStreamURIReceived(@Nonnull OnvifDevice device, - @Nonnull OnvifMediaProfile profile, @Nonnull String uri) { - - } -}); -``` - -## UPnP ---- - -With the ```UPnPManager``` it is possible to retrieve device information from a locally connected UPnP device. A ```UPnPDevice``` can be created manually or discovered from the ```DiscoveryManager``` using ```discovery.discover(DiscoveryMode.UPNP)``` - -```java -UPnPDevice device = new UPnPDevice("192.168.0.160"); -device.setLocation("http://192.168.0.160:49152/rootdesc1.xml"); -UPnPManager uPnPManager = new UPnPManager(); -uPnPManager.getDeviceInformation(device, new UPnPDeviceInformationListener() { - @Override - public void onDeviceInformationReceived(@Nonnull UPnPDevice device, - @Nonnull UPnPDeviceInformation information) { - Log.i(TAG, device.getHostName() + ": " + information.getFriendlyName()); - } - @Override - public void onError(@Nonnull UPnPDevice onvifDevice, int errorCode, String errorMessage) { - Log.e(TAG, "Error: " + errorMessage); - } -}); -``` - -## Custom requests ---- - -It is possible to implement your custom ONVIF request by creating a new class and implementing the ```OnvifRequest``` interface and overriding the ```getXml()``` and ```getType()``` methods. - -```java -public class PTZRequest implements OnvifRequest { - @Override - public String getXml() { - return "" + - "false" + - ""; - } - @Override - public OnvifType getType() { - return OnvifType.CUSTOM; - } -} -``` - -and send it to the appropriate ```OnvifDevice```: - -```java -onvifManager.sendOnvifRequest(device, new PTZRequest()); -``` - -Use the ```OnvifResponseListener``` to receive responses from your custom requests. - -## Android ---- -In order to receive multicasts packets on your Android device, you'll have to acquire a lock on your WifiManager before making a discovery. Make sure to release the lock once the discovery is completed. More information can be found here: https://developer.android.com/reference/android/net/wifi/WifiManager.MulticastLock - -```java -private void lockMulticast() { - WifiManager wifi = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); - if (wifi == null) - return; - - WifiManager.MulticastLock lock = wifi.createMulticastLock("ONVIF"); - lock.acquire(); -} -``` - -Download --------- - -Download [the latest JAR][2] or grab via Maven: -```xml - - be.teletask.onvif - onvif - 1.0.0 - -``` -or Gradle: -```groovy -compile 'be.teletask.onvif:onvif:1.0.0' -``` - -## Todos - - - Implementation ONVIF version management - - Implementation PTZ - -## Pull Requests ---- -Feel free to send pull requests. - -License -======= - - Copyright 2018 TELETASK BVBA. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -[2]: https://bintray.com/tomasverhelst/ONVIF-Java/ONVIF-Java/1.0.0#files/be/teletask/onvif/onvif/1.0.0 - +# ONVIF-Java +--- +[![](https://jitpack.io/v/RootSoft/ONVIF-Java.svg)](https://jitpack.io/#RootSoft/ONVIF-Java) + + +

+ +

+ +ONVIF is an open industry forum that provides and promotes standardized interfaces for effective interoperability of IP-based physical security products. ONVIF was created to make a standard way of how IP products within CCTV and other security areas can communicate with each other. + + +## Features + + - **ONVIF & UPnP discovery** + - ONVIF device management (Services, device information, media profiles, raw media stream uri) + - UPnP device information + - Easily extendable with your own requests + - **Android supported!** + - [**Kotlin Coroutines support**](KOTLIN.md) + +## Discovery +--- +The OnvifDiscovery class uses the **Web Services Dynamic Discovery (WS-Discovery)**. This is a technical specification that defines a multicast discovery protocol to locate services on a local network. It operates over TCP and UDP port ```3702``` and uses IP multicast address ```239.255.255.250```. As the name suggests, the actual communication between nodes is done using web services standards, notably **SOAP-over-UDP**. + +With WS-Discovery, the discovery tool puts SSDP queries on the network from its unicast address to ```239.255.255.250``` multicast address, sending them to the well-known UDP port 3702. The device receives the query, and answers to the discovery tool's unicast IP address from its unicast IP address. The reply contains information about the Web Services (WS) available on the device. + +**UPnP** works in a very similar way, but on a different UDP port (```1900```). +Compared to the WS-Discovery, the UPnP is intended for a general use (data sharing, communication, entertainment). + +```java +DiscoveryManager manager = new DiscoveryManager(); +manager.setDiscoveryTimeout(10000); +manager.discover(new DiscoveryListener() { + @Override + public void onDiscoveryStarted() { + System.out.println("Discovery started"); + } + + @Override + public void onDevicesFound(List devices) { + for (Device device : devices) + System.out.println("Devices found: " + device.getHostName()); + } +}); +``` + +## ONVIF +--- + +With the ```OnvifManager``` class it is possible to send requests to an ONVIF-supported device. All requests are sent asynchronously and you can use the ```OnvifResponseListener``` for errors and custom response handling. It is possible to create your own ```OnvifDevice``` or retrieve a list from the ```discover``` method in the ```DiscoveryManager``` + +```java +onvifManager = new OnvifManager(); +onvifManager.setOnvifResponseListener(this); +OnvifDevice device = new OnvifDevice("192.168.0.131", "username", "password"); +``` + +### Services +Returns information about services on the device. + +```java +onvifManager.getServices(device, new OnvifServicesListener() { + @Override + public void onServicesReceived(@Nonnull OnvifDevice onvifDevice, OnvifServices services) { + + } +}); +``` + +### Device information +Returns basic device information from the device. This includes the manufacturer, serial number, hardwareId, ... + +```java +onvifManager.getDeviceInformation(device, new OnvifDeviceInformationListener() { + @Override + public void onDeviceInformationReceived(@Nonnull OnvifDevice device, + @Nonnull OnvifDeviceInformation deviceInformation) { + + } +}); +``` + +### Media Profiles +Returns pre-configured or dynamically configured profiles. This command lists all configured profiles in a device. The client does not need to know the media profile in order to use the command. + +```java +onvifManager.getMediaProfiles(device, new OnvifMediaProfilesListener() { + @Override + public void onMediaProfilesReceived(@Nonnull OnvifDevice device, + @Nonnull List mediaProfiles) { + + } +}); +``` + +### Media Stream URI +Returns a raw media stream URI that remains valid indefinitely even if the profile is changed. + +```java +onvifManager.getMediaStreamURI(device, mediaProfiles.get(0), new OnvifMediaStreamURIListener() { + @Override + public void onMediaStreamURIReceived(@Nonnull OnvifDevice device, + @Nonnull OnvifMediaProfile profile, @Nonnull String uri) { + + } +}); +``` + +## UPnP +--- + +With the ```UPnPManager``` it is possible to retrieve device information from a locally connected UPnP device. A ```UPnPDevice``` can be created manually or discovered from the ```DiscoveryManager``` using ```discovery.discover(DiscoveryMode.UPNP)``` + +```java +UPnPDevice device = new UPnPDevice("192.168.0.160"); +device.setLocation("http://192.168.0.160:49152/rootdesc1.xml"); +UPnPManager uPnPManager = new UPnPManager(); +uPnPManager.getDeviceInformation(device, new UPnPDeviceInformationListener() { + @Override + public void onDeviceInformationReceived(@Nonnull UPnPDevice device, + @Nonnull UPnPDeviceInformation information) { + Log.i(TAG, device.getHostName() + ": " + information.getFriendlyName()); + } + @Override + public void onError(@Nonnull UPnPDevice onvifDevice, int errorCode, String errorMessage) { + Log.e(TAG, "Error: " + errorMessage); + } +}); +``` + +## Custom requests +--- + +It is possible to implement your custom ONVIF request by creating a new class and implementing the ```OnvifRequest``` interface and overriding the ```getXml()``` and ```getType()``` methods. + +```java +public class PTZRequest implements OnvifRequest { + @Override + public String getXml() { + return "" + + "false" + + ""; + } + @Override + public OnvifType getType() { + return OnvifType.CUSTOM; + } +} +``` + +and send it to the appropriate ```OnvifDevice```: + +```java +onvifManager.sendOnvifRequest(device, new PTZRequest()); +``` + +Use the ```OnvifResponseListener``` to receive responses from your custom requests. + +## Android +--- +In order to receive multicasts packets on your Android device, you'll have to acquire a lock on your WifiManager before making a discovery. Make sure to release the lock once the discovery is completed. More information can be found here: https://developer.android.com/reference/android/net/wifi/WifiManager.MulticastLock + +```java +private void lockMulticast() { + WifiManager wifi = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); + if (wifi == null) + return; + + WifiManager.MulticastLock lock = wifi.createMulticastLock("ONVIF"); + lock.acquire(); +} +``` + +Download +-------- + +Download [the latest JAR][2] or grab via Maven: +```xml + + com.github.rootsoft + onvif-java + 1.0.3 + +``` +or Gradle: +```groovy +compile 'com.github.rootsoft:onvif-java:1.0.3' +``` + +## Todos + + - Implementation ONVIF version management + - Implementation PTZ + +## Pull Requests +--- +Feel free to send pull requests. + +License +======= + + Copyright 2018 TELETASK BVBA. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +[2]: https://bintray.com/tomasverhelst/ONVIF-Java/ONVIF-Java/1.0.0#files/be/teletask/onvif/onvif/1.0.0 + diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..1c51889 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,28 @@ +plugins { + kotlin("jvm") version "1.3.21" + maven +} + +repositories { + mavenCentral() + jcenter() +} + +group = "be.teletask.onvif" +version = "1.0.3" + +dependencies { + implementation(kotlin("stdlib-jdk8")) + implementation("org.jetbrains", "annotations", "15.0") + implementation("net.sf.kxml", "kxml2", "2.3.0") + implementation("com.squareup.okhttp3", "okhttp", "3.11.0") + implementation("com.burgstaller", "okhttp-digest", "1.18") + implementation("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.1.1") +} + +val sourcesJar by tasks.creating(Jar::class) { + classifier = "sources" + from(sourceSets["main"].allSource) +} + +artifacts.add("archives", sourcesJar) \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..91ca28c8b802289c3a438766657a5e98f20eff03 GIT binary patch literal 54413 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 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/lib/.gitignore b/lib/.gitignore deleted file mode 100644 index deee1b6..0000000 --- a/lib/.gitignore +++ /dev/null @@ -1,174 +0,0 @@ - -# Created by https://www.gitignore.io/api/java,android,intellij - -### Android ### -# Built application files -*.apk -*.ap_ - -# Files for the ART/Dalvik VM -*.dex - -# Java class files -*.class - -# Generated files -bin/ -gen/ -out/ - -# Gradle files -.gradle/ -build/ - -# Local configuration file (sdk path, etc) -local.properties - -# Proguard folder generated by Eclipse -proguard/ - -# Log Files -*.log - -# Android Studio Navigation editor temp files -.navigation/ - -# Android Studio captures folder -captures/ - -# IntelliJ -*.iml -.idea -.idea/workspace.xml -.idea/tasks.xml -.idea/gradle.xml -.idea/assetWizardSettings.xml -.idea/dictionaries -.idea/libraries -.idea/caches - -# Keystore files -# Uncomment the following line if you do not want to check your keystore files in. -#*.jks - -# External native build folder generated in Android Studio 2.2 and later -.externalNativeBuild - -# Google Services (e.g. APIs or Firebase) -google-services.json - -# Freeline -freeline.py -freeline/ -freeline_project_description.json - -# fastlane -fastlane/report.xml -fastlane/Preview.html -fastlane/screenshots -fastlane/test_output -fastlane/readme.md - -### Android Patch ### -gen-external-apklibs - -### Intellij ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -# Generated files -.idea/**/contentModel.xml - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/modules.xml -# .idea/*.iml -# .idea/modules - -# CMake -cmake-build-*/ - -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# File-based project format -*.iws - -# IntelliJ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# Editor-based Rest Client -.idea/httpRequests - -### Intellij Patch ### -# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 - -# *.iml -# modules.xml -# .idea/misc.xml -# *.ipr - -# Sonarlint plugin -.idea/sonarlint - -### Java ### -# Compiled class file - -# Log file - -# BlueJ files -*.ctxt - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* - - -# End of https://www.gitignore.io/api/java,android,intellij \ No newline at end of file diff --git a/lib/build.gradle b/lib/build.gradle deleted file mode 100644 index 1a2d811..0000000 --- a/lib/build.gradle +++ /dev/null @@ -1,150 +0,0 @@ -buildscript { - repositories { - jcenter() - } - dependencies { - classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1' - classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3' - } -} - -plugins { - id 'java' -} - -group 'be.teletask.onvif' -version '1.0.0' - -sourceCompatibility = 1.8 - -if (JavaVersion.current().isJava8Compatible()) { - allprojects { - tasks.withType(Javadoc) { - options.addStringOption('Xdoclint:none', '-quiet') - } - } -} - -repositories { - mavenCentral() - jcenter() -} - -dependencies { - testCompile group: 'junit', name: 'junit', version: '4.12' - - //Annotations - compile group: 'org.jetbrains', name: 'annotations', version: '15.0' - - //XML parser - compile group: 'net.sf.kxml', name: 'kxml2', version: '2.3.0' - - //OkHttp - compile 'com.squareup.okhttp3:okhttp:3.11.0' - - //OkHttp Digest - compile 'com.burgstaller:okhttp-digest:1.18' -} - -ext { - bintrayRepo = 'ONVIF-Java' - bintrayName = 'ONVIF-Java' - - publishedGroupId = 'be.teletask.onvif' - libraryName = 'ONVIF-Java' - artifact = 'onvif' - - libraryDescription = 'A Java client library to discover, control and manage ONVIF-supported devices.' - - siteUrl = 'https://github.com/RootSoft/ONVIF-Java' - gitUrl = 'https://github.com/RootSoft/ONVIF-Java.git' - - libraryVersion = '1.0.2' - - developerId = 'tomasverhelst' - developerName = 'Tomas Verhelst' - developerEmail = 'tve@teletask.be' - - licenseName = 'The Apache Software License, Version 2.0' - licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt' - allLicenses = ["Apache-2.0"] -} - -apply plugin: 'com.github.dcendents.android-maven' -apply plugin: 'com.jfrog.bintray' - -group = publishedGroupId -version = libraryVersion - -install { - repositories.mavenInstaller { - pom.project { - packaging 'jar' - groupId publishedGroupId - artifactId artifact - - name libraryName - description libraryDescription - url siteUrl - - licenses { - license { - name licenseName - url licenseUrl - } - } - developers { - developer { - id developerId - name developerName - email developerEmail - } - } - scm { - connection gitUrl - developerConnection gitUrl - url siteUrl - } - } - } -} - -task sourcesJar(type: Jar) { - classifier = 'sources' - from sourceSets.main.java.srcDirs -} - -task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = 'javadoc' - from javadoc.destinationDir -} - -artifacts { - archives javadocJar - archives sourcesJar -} - -Properties properties = new Properties() -properties.load(project.rootProject.file('local.properties').newDataInputStream()) - -bintray { - user = properties.getProperty("bintray.user") - key = properties.getProperty("bintray.apikey") - - configurations = ['archives'] - pkg { - repo = bintrayRepo - name = bintrayName - desc = libraryDescription - websiteUrl = siteUrl - vcsUrl = gitUrl - licenses = allLicenses - dryRun = false - publish = true - override = false - publicDownloadNumbers = true - version { - desc = libraryDescription - } - } -} diff --git a/lib/settings.gradle b/lib/settings.gradle deleted file mode 100644 index bab79fc..0000000 --- a/lib/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ -rootProject.name = 'onvif' - diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..818c0ff --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,11 @@ +pluginManagement { + resolutionStrategy { + eachPlugin { + if (requested.id.namespace!!.startsWith("org.jetbrains.kotlin")) { + useVersion(requested.version) + } + } + } +} + +rootProject.name = "ONVIF-Java" \ No newline at end of file diff --git a/lib/src/main/java/be/teletask/onvif/DiscoveryManager.java b/src/main/java/be/teletask/onvif/DiscoveryManager.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/DiscoveryManager.java rename to src/main/java/be/teletask/onvif/DiscoveryManager.java diff --git a/lib/src/main/java/be/teletask/onvif/DiscoveryMode.java b/src/main/java/be/teletask/onvif/DiscoveryMode.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/DiscoveryMode.java rename to src/main/java/be/teletask/onvif/DiscoveryMode.java diff --git a/lib/src/main/java/be/teletask/onvif/DiscoveryThread.java b/src/main/java/be/teletask/onvif/DiscoveryThread.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/DiscoveryThread.java rename to src/main/java/be/teletask/onvif/DiscoveryThread.java diff --git a/lib/src/main/java/be/teletask/onvif/OnvifDiscovery.java b/src/main/java/be/teletask/onvif/OnvifDiscovery.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/OnvifDiscovery.java rename to src/main/java/be/teletask/onvif/OnvifDiscovery.java diff --git a/lib/src/main/java/be/teletask/onvif/OnvifExecutor.java b/src/main/java/be/teletask/onvif/OnvifExecutor.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/OnvifExecutor.java rename to src/main/java/be/teletask/onvif/OnvifExecutor.java diff --git a/lib/src/main/java/be/teletask/onvif/OnvifManager.java b/src/main/java/be/teletask/onvif/OnvifManager.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/OnvifManager.java rename to src/main/java/be/teletask/onvif/OnvifManager.java diff --git a/lib/src/main/java/be/teletask/onvif/OnvifUtils.java b/src/main/java/be/teletask/onvif/OnvifUtils.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/OnvifUtils.java rename to src/main/java/be/teletask/onvif/OnvifUtils.java diff --git a/lib/src/main/java/be/teletask/onvif/OnvifXMLBuilder.java b/src/main/java/be/teletask/onvif/OnvifXMLBuilder.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/OnvifXMLBuilder.java rename to src/main/java/be/teletask/onvif/OnvifXMLBuilder.java diff --git a/lib/src/main/java/be/teletask/onvif/listeners/DiscoveryCallback.java b/src/main/java/be/teletask/onvif/listeners/DiscoveryCallback.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/listeners/DiscoveryCallback.java rename to src/main/java/be/teletask/onvif/listeners/DiscoveryCallback.java diff --git a/lib/src/main/java/be/teletask/onvif/listeners/DiscoveryListener.java b/src/main/java/be/teletask/onvif/listeners/DiscoveryListener.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/listeners/DiscoveryListener.java rename to src/main/java/be/teletask/onvif/listeners/DiscoveryListener.java diff --git a/lib/src/main/java/be/teletask/onvif/listeners/OnvifDeviceInformationListener.java b/src/main/java/be/teletask/onvif/listeners/OnvifDeviceInformationListener.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/listeners/OnvifDeviceInformationListener.java rename to src/main/java/be/teletask/onvif/listeners/OnvifDeviceInformationListener.java diff --git a/lib/src/main/java/be/teletask/onvif/listeners/OnvifMediaProfilesListener.java b/src/main/java/be/teletask/onvif/listeners/OnvifMediaProfilesListener.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/listeners/OnvifMediaProfilesListener.java rename to src/main/java/be/teletask/onvif/listeners/OnvifMediaProfilesListener.java diff --git a/lib/src/main/java/be/teletask/onvif/listeners/OnvifMediaStreamURIListener.java b/src/main/java/be/teletask/onvif/listeners/OnvifMediaStreamURIListener.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/listeners/OnvifMediaStreamURIListener.java rename to src/main/java/be/teletask/onvif/listeners/OnvifMediaStreamURIListener.java diff --git a/lib/src/main/java/be/teletask/onvif/listeners/OnvifResponseListener.java b/src/main/java/be/teletask/onvif/listeners/OnvifResponseListener.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/listeners/OnvifResponseListener.java rename to src/main/java/be/teletask/onvif/listeners/OnvifResponseListener.java diff --git a/lib/src/main/java/be/teletask/onvif/listeners/OnvifServicesListener.java b/src/main/java/be/teletask/onvif/listeners/OnvifServicesListener.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/listeners/OnvifServicesListener.java rename to src/main/java/be/teletask/onvif/listeners/OnvifServicesListener.java diff --git a/lib/src/main/java/be/teletask/onvif/models/Device.java b/src/main/java/be/teletask/onvif/models/Device.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/models/Device.java rename to src/main/java/be/teletask/onvif/models/Device.java diff --git a/lib/src/main/java/be/teletask/onvif/models/DeviceType.java b/src/main/java/be/teletask/onvif/models/DeviceType.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/models/DeviceType.java rename to src/main/java/be/teletask/onvif/models/DeviceType.java diff --git a/lib/src/main/java/be/teletask/onvif/models/DiscoveryPacket.java b/src/main/java/be/teletask/onvif/models/DiscoveryPacket.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/models/DiscoveryPacket.java rename to src/main/java/be/teletask/onvif/models/DiscoveryPacket.java diff --git a/lib/src/main/java/be/teletask/onvif/models/DiscoveryType.java b/src/main/java/be/teletask/onvif/models/DiscoveryType.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/models/DiscoveryType.java rename to src/main/java/be/teletask/onvif/models/DiscoveryType.java diff --git a/lib/src/main/java/be/teletask/onvif/models/OnvifDevice.java b/src/main/java/be/teletask/onvif/models/OnvifDevice.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/models/OnvifDevice.java rename to src/main/java/be/teletask/onvif/models/OnvifDevice.java diff --git a/lib/src/main/java/be/teletask/onvif/models/OnvifDeviceInformation.java b/src/main/java/be/teletask/onvif/models/OnvifDeviceInformation.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/models/OnvifDeviceInformation.java rename to src/main/java/be/teletask/onvif/models/OnvifDeviceInformation.java diff --git a/lib/src/main/java/be/teletask/onvif/models/OnvifMediaProfile.java b/src/main/java/be/teletask/onvif/models/OnvifMediaProfile.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/models/OnvifMediaProfile.java rename to src/main/java/be/teletask/onvif/models/OnvifMediaProfile.java diff --git a/lib/src/main/java/be/teletask/onvif/models/OnvifPacket.java b/src/main/java/be/teletask/onvif/models/OnvifPacket.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/models/OnvifPacket.java rename to src/main/java/be/teletask/onvif/models/OnvifPacket.java diff --git a/lib/src/main/java/be/teletask/onvif/models/OnvifServices.java b/src/main/java/be/teletask/onvif/models/OnvifServices.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/models/OnvifServices.java rename to src/main/java/be/teletask/onvif/models/OnvifServices.java diff --git a/lib/src/main/java/be/teletask/onvif/models/OnvifType.java b/src/main/java/be/teletask/onvif/models/OnvifType.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/models/OnvifType.java rename to src/main/java/be/teletask/onvif/models/OnvifType.java diff --git a/lib/src/main/java/be/teletask/onvif/models/UPnPDevice.java b/src/main/java/be/teletask/onvif/models/UPnPDevice.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/models/UPnPDevice.java rename to src/main/java/be/teletask/onvif/models/UPnPDevice.java diff --git a/lib/src/main/java/be/teletask/onvif/parsers/DiscoveryParser.java b/src/main/java/be/teletask/onvif/parsers/DiscoveryParser.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/parsers/DiscoveryParser.java rename to src/main/java/be/teletask/onvif/parsers/DiscoveryParser.java diff --git a/lib/src/main/java/be/teletask/onvif/parsers/GetDeviceInformationParser.java b/src/main/java/be/teletask/onvif/parsers/GetDeviceInformationParser.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/parsers/GetDeviceInformationParser.java rename to src/main/java/be/teletask/onvif/parsers/GetDeviceInformationParser.java diff --git a/lib/src/main/java/be/teletask/onvif/parsers/GetMediaProfilesParser.java b/src/main/java/be/teletask/onvif/parsers/GetMediaProfilesParser.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/parsers/GetMediaProfilesParser.java rename to src/main/java/be/teletask/onvif/parsers/GetMediaProfilesParser.java diff --git a/lib/src/main/java/be/teletask/onvif/parsers/GetMediaStreamParser.java b/src/main/java/be/teletask/onvif/parsers/GetMediaStreamParser.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/parsers/GetMediaStreamParser.java rename to src/main/java/be/teletask/onvif/parsers/GetMediaStreamParser.java diff --git a/lib/src/main/java/be/teletask/onvif/parsers/GetServicesParser.java b/src/main/java/be/teletask/onvif/parsers/GetServicesParser.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/parsers/GetServicesParser.java rename to src/main/java/be/teletask/onvif/parsers/GetServicesParser.java diff --git a/lib/src/main/java/be/teletask/onvif/parsers/OnvifParser.java b/src/main/java/be/teletask/onvif/parsers/OnvifParser.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/parsers/OnvifParser.java rename to src/main/java/be/teletask/onvif/parsers/OnvifParser.java diff --git a/lib/src/main/java/be/teletask/onvif/parsers/UPnPParser.java b/src/main/java/be/teletask/onvif/parsers/UPnPParser.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/parsers/UPnPParser.java rename to src/main/java/be/teletask/onvif/parsers/UPnPParser.java diff --git a/lib/src/main/java/be/teletask/onvif/requests/GetDeviceInformationRequest.java b/src/main/java/be/teletask/onvif/requests/GetDeviceInformationRequest.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/requests/GetDeviceInformationRequest.java rename to src/main/java/be/teletask/onvif/requests/GetDeviceInformationRequest.java diff --git a/lib/src/main/java/be/teletask/onvif/requests/GetMediaProfilesRequest.java b/src/main/java/be/teletask/onvif/requests/GetMediaProfilesRequest.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/requests/GetMediaProfilesRequest.java rename to src/main/java/be/teletask/onvif/requests/GetMediaProfilesRequest.java diff --git a/lib/src/main/java/be/teletask/onvif/requests/GetMediaStreamRequest.java b/src/main/java/be/teletask/onvif/requests/GetMediaStreamRequest.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/requests/GetMediaStreamRequest.java rename to src/main/java/be/teletask/onvif/requests/GetMediaStreamRequest.java diff --git a/lib/src/main/java/be/teletask/onvif/requests/GetServicesRequest.java b/src/main/java/be/teletask/onvif/requests/GetServicesRequest.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/requests/GetServicesRequest.java rename to src/main/java/be/teletask/onvif/requests/GetServicesRequest.java diff --git a/lib/src/main/java/be/teletask/onvif/requests/OnvifRequest.java b/src/main/java/be/teletask/onvif/requests/OnvifRequest.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/requests/OnvifRequest.java rename to src/main/java/be/teletask/onvif/requests/OnvifRequest.java diff --git a/lib/src/main/java/be/teletask/onvif/responses/OnvifResponse.java b/src/main/java/be/teletask/onvif/responses/OnvifResponse.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/responses/OnvifResponse.java rename to src/main/java/be/teletask/onvif/responses/OnvifResponse.java diff --git a/lib/src/main/java/be/teletask/onvif/upnp/UPnPDeviceInformation.java b/src/main/java/be/teletask/onvif/upnp/UPnPDeviceInformation.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/upnp/UPnPDeviceInformation.java rename to src/main/java/be/teletask/onvif/upnp/UPnPDeviceInformation.java diff --git a/lib/src/main/java/be/teletask/onvif/upnp/UPnPDeviceInformationListener.java b/src/main/java/be/teletask/onvif/upnp/UPnPDeviceInformationListener.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/upnp/UPnPDeviceInformationListener.java rename to src/main/java/be/teletask/onvif/upnp/UPnPDeviceInformationListener.java diff --git a/lib/src/main/java/be/teletask/onvif/upnp/UPnPExecutor.java b/src/main/java/be/teletask/onvif/upnp/UPnPExecutor.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/upnp/UPnPExecutor.java rename to src/main/java/be/teletask/onvif/upnp/UPnPExecutor.java diff --git a/lib/src/main/java/be/teletask/onvif/upnp/UPnPManager.java b/src/main/java/be/teletask/onvif/upnp/UPnPManager.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/upnp/UPnPManager.java rename to src/main/java/be/teletask/onvif/upnp/UPnPManager.java diff --git a/lib/src/main/java/be/teletask/onvif/upnp/UPnPResponseListener.java b/src/main/java/be/teletask/onvif/upnp/UPnPResponseListener.java similarity index 100% rename from lib/src/main/java/be/teletask/onvif/upnp/UPnPResponseListener.java rename to src/main/java/be/teletask/onvif/upnp/UPnPResponseListener.java diff --git a/src/main/kotlin/be/teletask/onvif/coroutines/Coroutines.kt b/src/main/kotlin/be/teletask/onvif/coroutines/Coroutines.kt new file mode 100644 index 0000000..c79fc99 --- /dev/null +++ b/src/main/kotlin/be/teletask/onvif/coroutines/Coroutines.kt @@ -0,0 +1,59 @@ +package be.teletask.onvif.coroutines + +import be.teletask.onvif.DiscoveryManager +import be.teletask.onvif.OnvifManager +import be.teletask.onvif.listeners.DiscoveryListener +import be.teletask.onvif.listeners.OnvifDeviceInformationListener +import be.teletask.onvif.listeners.OnvifMediaProfilesListener +import be.teletask.onvif.listeners.OnvifMediaStreamURIListener +import be.teletask.onvif.models.Device +import be.teletask.onvif.models.OnvifDeviceInformation +import be.teletask.onvif.models.OnvifMediaProfile +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlin.coroutines.resume + +suspend fun awaitDeviceInformation(block: (OnvifDeviceInformationListener) -> Unit): OnvifDeviceInformation = + suspendCancellableCoroutine { cont -> + block(OnvifDeviceInformationListener { _, deviceInformation -> + cont.resume(deviceInformation) + }) + } + +suspend fun awaitDeviceDiscovery(onDiscoveryStarted: ()->Unit = {}, block: (DiscoveryListener) -> Unit): List = + suspendCancellableCoroutine { cont -> + block(object : DiscoveryListener { + override fun onDevicesFound(devices: List) { + cont.resume(devices) + } + + override fun onDiscoveryStarted() = onDiscoveryStarted() + }) + } + +suspend fun discoverDevices(configure: DiscoveryManager.()->Unit = {}) = DiscoveryManager().run { + configure() + awaitDeviceDiscovery { + discover(it) + } +} + +suspend fun awaitDeviceMediaStramUri(block: (OnvifMediaStreamURIListener) -> Unit): String = + suspendCancellableCoroutine { cont -> + block(OnvifMediaStreamURIListener { _, _, uri -> + cont.resume(uri) + }) + } + +suspend fun awaitDeviceMediaProfiles(block: (OnvifMediaProfilesListener) -> Unit): List = + suspendCancellableCoroutine { cont -> + block(OnvifMediaProfilesListener { _, profiles -> + cont.resume(profiles) + }) + } + +suspend fun awaitDeviceInformations(block: (OnvifDeviceInformationListener) -> Unit): OnvifDeviceInformation = + suspendCancellableCoroutine { cont -> + block(OnvifDeviceInformationListener { _, information -> + cont.resume(information) + }) + } \ No newline at end of file From 4467300cea83c44fe79b83646787ea3a1582a1d3 Mon Sep 17 00:00:00 2001 From: Lamba Date: Mon, 18 Feb 2019 13:55:11 +0100 Subject: [PATCH 02/12] Added Kotlin coroutines wrappers, moved publishing on Jitpack and rewrote the Gradle script in Kotlin. Scaffolding overhaul to match standard Gradle project. --- .../buildOutputCleanup.lock | Bin 17 -> 0 bytes .gradle/buildOutputCleanup/cache.properties | 2 - .gradle/buildOutputCleanup/outputFiles.bin | Bin 18713 -> 0 bytes .idea/misc.xml | 6 - .idea/modules.xml | 8 -- .idea/workspace.xml | 118 ------------------ 6 files changed, 134 deletions(-) delete mode 100644 .gradle/buildOutputCleanup/buildOutputCleanup.lock delete mode 100644 .gradle/buildOutputCleanup/cache.properties delete mode 100644 .gradle/buildOutputCleanup/outputFiles.bin delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/workspace.xml diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock deleted file mode 100644 index a4b63eac8146a85bcf7a6f8fa0dff4e409c9f4c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 UcmZRUT=7GF)m053=b!2kdN diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties deleted file mode 100644 index fe6fbc3..0000000 --- a/.gradle/buildOutputCleanup/cache.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Fri Sep 07 13:23:41 CEST 2018 -gradle.version=4.8 diff --git a/.gradle/buildOutputCleanup/outputFiles.bin b/.gradle/buildOutputCleanup/outputFiles.bin deleted file mode 100644 index 5b524519df6a0d46046bd3e7a3f139623cea5899..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18713 zcmeI%Peg-Z9Ki8sT~b@yNW2}=Id&*@oEXV6x}<=`h3cw{K+2d-pR@4Ux5pg|7lCni zJ6hEL2lwXn(by znzF59ap@85RoT{-`kX)(%yEH4o^KM)6%!J$M;uf2PgB_(oeL{ z5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0;CBVOo!2)w!&4pA$^WG|;ZK$C IU-(1$1SlG_RsaA1 diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index e208459..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index f7ae735..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index 4736b15..0000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -