Tereius / libONVIF

Yet another ONVIF library
GNU General Public License v3.0
164 stars 47 forks source link

Authorization #2

Closed AndreWicked closed 5 years ago

AndreWicked commented 5 years ago

Hello! Thanks for the library!

I managed to use the discovery method, I received a list of uri, but I just can not figure out how to perform the authorization! I am new to onvif, I will be grateful for a small example!

Tereius commented 5 years ago

The ONVIF Core Specification states that the "Device Management" service is the entry point for all other services (refer Core Spec. 5.1.1). Consequently a ONVIF compliant devices returns the URL to its device management endpoint if you run the WS discovery (The URL for the device management service should be fixed to: http:///onvif/device_service).

So the first thing to do after the WS discovery would be to create a new OnvifDeviceClient instance and provide it with the URL pointing to the device management service (here). The next thing to do would be to set the credentials for authorization (here). From there on you should request all the other service endpoints your ONVIF device supports by calling GetServices() (here). For every endpoint you may want to instantiate a new client class that matches the service name (like OnvifAnalyticsClient, OnvifRecordingClient, OnvifMediaClient, ...) and call the ctor with the matching endpoint URL (here). For every service exists a class following the naming scheme Onvif*Client (* matches service name).

AndreWicked commented 5 years ago

Thank you very much! Your example really helped! I was able to authorize, get streams, but I ran into a problem. How can I transfer the protocol when I receive the uri? My code is:

   `auto builder = SoapCtx::Builder();
    auto ctx = builder
        .SetConnectTimeout(3000)
        .Build();

    OnvifDeviceClient *device = new OnvifDeviceClient(dev_endpoint, ctx, this);
    device->SetAuth(new_user, new_pswd, AUTO);

    Request<_tds__GetServices> request;
    request.IncludeCapability = false;
    auto servicesResponse = device->GetServices(request);
    if(servicesResponse) {
        for(auto service : servicesResponse.GetResultObject()->Service) {
            qDebug() << service->Namespace;
            if(service->Namespace == OnvifMediaClient::GetServiceNamespace()) {
                OnvifMediaClient *dev_media = new OnvifMediaClient(QUrl(qPrintable(service->XAddr)), ctx, this);
                dev_media->SetAuth(new_user, new_pswd, AUTO);
                Request<_trt__GetProfiles> request;
                auto mediaResponse = dev_media->GetProfiles(request);
                if(mediaResponse) {
                    for(auto profile : mediaResponse.GetResultObject()->Profiles) {
                        Request<_trt__GetStreamUri> stream_uri_request;
                        stream_uri_request.ProfileToken = profile->token;
                        stream_uri_request.StreamSetup->Stream = tt__StreamType(0);
                        stream_uri_request.StreamSetup->Transport->Protocol = tt__TransportProtocol(0);
                        auto streamUriResponse = dev_media->GetStreamUri(stream_uri_request);
                        if (streamUriResponse) {
                            json json_profile = json::object({{"dev_type", "onvif"}, {"profile_name", profile->Name.toUtf8()}, {"profile_uri", streamUriResponse.GetResultObject()->MediaUri->Uri.toUtf8()}});
                            json_profilesArray.push_back(json_profile);
                            qDebug() << streamUriResponse.GetResultObject()->MediaUri->Uri;
                        }
                        else {
                            qDebug() << "stream not given";
                        }
                    }
                    json json_response = {
                        {"type", "settings"},
                        {"status", "device_ok"},
                        {"data", json_profilesArray}
                    };

                    std::string response = json_response.dump();
                    int size = response.size();
                    _busy = true;
                    socket->write((const char*) &size, sizeof(int));
                    socket->write(response.c_str());
                    socket->waitForBytesWritten();
                }
                else {
                    qDebug() << "Couldn't get media properties" << mediaResponse.GetSoapFault();
                    json json_response = {
                        {"type", "settings"},
                        {"status", "device_fail"}
                    };

                    std::string response = json_response.dump();
                    int size = response.size();
                    _busy = true;
                    socket->write((const char*) &size, sizeof(int));
                    socket->write(response.c_str());
                    socket->waitForBytesWritten();
                }
            }
        }
    }`

When you try to transfer the protocol, the program fails. Thank you in advance!

Tereius commented 5 years ago

I don't understand. What do you mean by "How can I transfer the protocol" and where exactly does the crash happen?

AndreWicked commented 5 years ago
                   `Request<_trt__GetStreamUri> stream_uri_request;
                    stream_uri_request.ProfileToken = profile->token;
                    stream_uri_request.StreamSetup->Stream = tt__StreamType(0); //This 
                    stream_uri_request.StreamSetup->Transport->Protocol = tt__TransportProtocol(0); // And this
                    auto streamUriResponse = dev_media->GetStreamUri(stream_uri_request);
                    if (streamUriResponse) {
                        json json_profile = json::object({{"dev_type", "onvif"}, {"profile_name", profile->Name.toUtf8()}, {"profile_uri", streamUriResponse.GetResultObject()->MediaUri->Uri.toUtf8()}});
                        json_profilesArray.push_back(json_profile);
                        qDebug() << streamUriResponse.GetResultObject()->MediaUri->Uri;
                    }
                    else {
                        qDebug() << "stream not given";
                    }`

In lines 3 and 4, I want to specify the settings for the stream, obviously I am doing this incorrectly and a failure occurs on these lines.

Tereius commented 5 years ago

You have to instantiate the StreamSetup object first:

    stream_uri_request.StreamSetup = new tt__StreamSetup();
    stream_uri_request.StreamSetup->Stream = tt__StreamType::RTP_Unicast;
    stream_uri_request.StreamSetup->Transport = new tt__Transport();
    stream_uri_request.StreamSetup->Transport->Protocol = tt__TransportProtocol::UDP;
    auto streamUriResponse = dev_media->GetStreamUri(streamUriRequest);