CONNECTING THE CAMERA TO NETWORK

Getting the camera to connect to the network is still a device-dependent task. For my camera there's no ethernet port for configuration, so it relies on onboard microphone as I/O:

  1. connect to iOS app
  2. Specify WIFI connection info in the app
  3. The app modulates the info in audio wave and use phone's microphone to send the info to the camera
  4. Camera now connects to LAN

GETTING INFORMATION ABOUT THE CAMERA

Now this is where ONVIF shines. It defines a set of standard web services. The specs are here. Those services are in WSDL, so using .NET core to generate client code is really each:

Finding the device IP

I found the device IP by going into my router and searching by MAC (MAC is printed on a label on the camera). Alternatively, device IP can be obtained from the app.

Finding servive endpoints

The ONVIF core spec states that the device management (devicemgmt.wsdl) endpoint is fixed to http://onvif_host/onvif/device_service (section 5.1.1).

One useful tool is camera-probe. It's a NPM CLI that discovers devices on LAN. It was able to detect my camera.

Using WSDL clients

.NET Core has tool to generate WSDL client given WSDL documents. The two web services that're particularly useful are device.wsdl (or confusingly devicemgmt.wsdl) and media.wsdl.

1
2
3
4
5
dotnet tool install --global dotnet-svcutil
mkdir onvif && cd onvif
dotnet new console
dotnet-svcutil https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl -n '*,mgmt'
dotnet-svcutil https://www.onvif.org/ver10/media/wsdl/media.wsdl -n '*,media'

To use WSDL clients, the most important namespace is System.ServiceModel.*. Creating service clients requires specifying a binding (BasicHttpBinding), and the servicec endpoint:

1
2
3
4
5
6
7
8
9
var client = new DeviceClient(
new System.ServiceModel.BasicHttpBinding(),
new System.ServiceModel.EndpointAddress("http://192.168.0.19:80/onvif/device_service")
);

var mediaClient = new MediaClient(
new System.ServiceModel.BasicHttpBinding(),
new System.ServiceModel.EndpointAddress("http://192.168.0.19:80/onvif/device_service")
);

I used below code to get various information about the device, the streams, and the detail for each stream:

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
System.Console.WriteLine(js(
await client.GetCapabilitiesAsync(new CapabilityCategory[] {CapabilityCategory.All})
));

System.Console.WriteLine(js(
await mediaClient.GetServiceCapabilitiesAsync()
));

System.Console.WriteLine(js(
await mediaClient.GetProfilesAsync()
));

System.Console.WriteLine(js(
await mediaClient.GetVideoSourceConfigurationAsync("stream0")
));

System.Console.WriteLine(js(
await mediaClient.GetStreamUriAsync(
new StreamSetup()
{
Stream = StreamType.RTPUnicast,
Transport = new Transport
{
Protocol = TransportProtocol.HTTP,
},
},
"profile_VideoSource_1"
)
));

The GetStreamUriAsync call gives the RTSP stream address for stream profile profile_VideoSource_1: rtsp://192.168.0.xx:2600/stream0.

Note that this stream needs authentication. The user and password is, unfortunately, device-dependent. For my device, the instrucment is mentioned at Amiccom website under NVR section. It basically says the username is admin, the password must be obtained from the app. I do see a generated password in the app.

So I was able to connect to the stream in VLC using the following URI:

rtsp://<username>:<password>@<device_addr>:2600/stream0`

References