601 lines
17 KiB
Go
601 lines
17 KiB
Go
package onvif
|
|
|
|
import (
|
|
"context"
|
|
"encoding/xml"
|
|
"fmt"
|
|
|
|
"github.com/0x524a/onvif-go/internal/soap"
|
|
)
|
|
|
|
// Media service namespace
|
|
const mediaNamespace = "http://www.onvif.org/ver10/media/wsdl"
|
|
|
|
// GetProfiles retrieves all media profiles
|
|
func (c *Client) GetProfiles(ctx context.Context) ([]*Profile, error) {
|
|
endpoint := c.mediaEndpoint
|
|
if endpoint == "" {
|
|
endpoint = c.endpoint
|
|
}
|
|
|
|
type GetProfiles struct {
|
|
XMLName xml.Name `xml:"trt:GetProfiles"`
|
|
Xmlns string `xml:"xmlns:trt,attr"`
|
|
}
|
|
|
|
type GetProfilesResponse struct {
|
|
XMLName xml.Name `xml:"GetProfilesResponse"`
|
|
Profiles []struct {
|
|
Token string `xml:"token,attr"`
|
|
Name string `xml:"Name"`
|
|
VideoSourceConfiguration *struct {
|
|
Token string `xml:"token,attr"`
|
|
Name string `xml:"Name"`
|
|
UseCount int `xml:"UseCount"`
|
|
SourceToken string `xml:"SourceToken"`
|
|
Bounds *struct {
|
|
X int `xml:"x,attr"`
|
|
Y int `xml:"y,attr"`
|
|
Width int `xml:"width,attr"`
|
|
Height int `xml:"height,attr"`
|
|
} `xml:"Bounds"`
|
|
} `xml:"VideoSourceConfiguration"`
|
|
VideoEncoderConfiguration *struct {
|
|
Token string `xml:"token,attr"`
|
|
Name string `xml:"Name"`
|
|
UseCount int `xml:"UseCount"`
|
|
Encoding string `xml:"Encoding"`
|
|
Resolution *struct {
|
|
Width int `xml:"Width"`
|
|
Height int `xml:"Height"`
|
|
} `xml:"Resolution"`
|
|
Quality float64 `xml:"Quality"`
|
|
RateControl *struct {
|
|
FrameRateLimit int `xml:"FrameRateLimit"`
|
|
EncodingInterval int `xml:"EncodingInterval"`
|
|
BitrateLimit int `xml:"BitrateLimit"`
|
|
} `xml:"RateControl"`
|
|
} `xml:"VideoEncoderConfiguration"`
|
|
PTZConfiguration *struct {
|
|
Token string `xml:"token,attr"`
|
|
Name string `xml:"Name"`
|
|
UseCount int `xml:"UseCount"`
|
|
NodeToken string `xml:"NodeToken"`
|
|
} `xml:"PTZConfiguration"`
|
|
} `xml:"Profiles"`
|
|
}
|
|
|
|
req := GetProfiles{
|
|
Xmlns: mediaNamespace,
|
|
}
|
|
|
|
var resp GetProfilesResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, endpoint, "", req, &resp); err != nil {
|
|
return nil, fmt.Errorf("GetProfiles failed: %w", err)
|
|
}
|
|
|
|
profiles := make([]*Profile, len(resp.Profiles))
|
|
for i, p := range resp.Profiles {
|
|
profile := &Profile{
|
|
Token: p.Token,
|
|
Name: p.Name,
|
|
}
|
|
|
|
if p.VideoSourceConfiguration != nil {
|
|
profile.VideoSourceConfiguration = &VideoSourceConfiguration{
|
|
Token: p.VideoSourceConfiguration.Token,
|
|
Name: p.VideoSourceConfiguration.Name,
|
|
UseCount: p.VideoSourceConfiguration.UseCount,
|
|
SourceToken: p.VideoSourceConfiguration.SourceToken,
|
|
}
|
|
if p.VideoSourceConfiguration.Bounds != nil {
|
|
profile.VideoSourceConfiguration.Bounds = &IntRectangle{
|
|
X: p.VideoSourceConfiguration.Bounds.X,
|
|
Y: p.VideoSourceConfiguration.Bounds.Y,
|
|
Width: p.VideoSourceConfiguration.Bounds.Width,
|
|
Height: p.VideoSourceConfiguration.Bounds.Height,
|
|
}
|
|
}
|
|
}
|
|
|
|
if p.VideoEncoderConfiguration != nil {
|
|
profile.VideoEncoderConfiguration = &VideoEncoderConfiguration{
|
|
Token: p.VideoEncoderConfiguration.Token,
|
|
Name: p.VideoEncoderConfiguration.Name,
|
|
UseCount: p.VideoEncoderConfiguration.UseCount,
|
|
Encoding: p.VideoEncoderConfiguration.Encoding,
|
|
Quality: p.VideoEncoderConfiguration.Quality,
|
|
}
|
|
if p.VideoEncoderConfiguration.Resolution != nil {
|
|
profile.VideoEncoderConfiguration.Resolution = &VideoResolution{
|
|
Width: p.VideoEncoderConfiguration.Resolution.Width,
|
|
Height: p.VideoEncoderConfiguration.Resolution.Height,
|
|
}
|
|
}
|
|
if p.VideoEncoderConfiguration.RateControl != nil {
|
|
profile.VideoEncoderConfiguration.RateControl = &VideoRateControl{
|
|
FrameRateLimit: p.VideoEncoderConfiguration.RateControl.FrameRateLimit,
|
|
EncodingInterval: p.VideoEncoderConfiguration.RateControl.EncodingInterval,
|
|
BitrateLimit: p.VideoEncoderConfiguration.RateControl.BitrateLimit,
|
|
}
|
|
}
|
|
}
|
|
|
|
if p.PTZConfiguration != nil {
|
|
profile.PTZConfiguration = &PTZConfiguration{
|
|
Token: p.PTZConfiguration.Token,
|
|
Name: p.PTZConfiguration.Name,
|
|
UseCount: p.PTZConfiguration.UseCount,
|
|
NodeToken: p.PTZConfiguration.NodeToken,
|
|
}
|
|
}
|
|
|
|
profiles[i] = profile
|
|
}
|
|
|
|
return profiles, nil
|
|
}
|
|
|
|
// GetStreamURI retrieves the stream URI for a profile
|
|
func (c *Client) GetStreamURI(ctx context.Context, profileToken string) (*MediaURI, error) {
|
|
endpoint := c.mediaEndpoint
|
|
if endpoint == "" {
|
|
endpoint = c.endpoint
|
|
}
|
|
|
|
type GetStreamUri struct {
|
|
XMLName xml.Name `xml:"trt:GetStreamUri"`
|
|
Xmlns string `xml:"xmlns:trt,attr"`
|
|
Xmlnst string `xml:"xmlns:tt,attr"`
|
|
StreamSetup struct {
|
|
Stream string `xml:"tt:Stream"`
|
|
Transport struct {
|
|
Protocol string `xml:"tt:Protocol"`
|
|
} `xml:"tt:Transport"`
|
|
} `xml:"trt:StreamSetup"`
|
|
ProfileToken string `xml:"trt:ProfileToken"`
|
|
}
|
|
|
|
type GetStreamUriResponse struct {
|
|
XMLName xml.Name `xml:"GetStreamUriResponse"`
|
|
MediaUri struct {
|
|
Uri string `xml:"Uri"`
|
|
InvalidAfterConnect bool `xml:"InvalidAfterConnect"`
|
|
InvalidAfterReboot bool `xml:"InvalidAfterReboot"`
|
|
Timeout string `xml:"Timeout"`
|
|
} `xml:"MediaUri"`
|
|
}
|
|
|
|
req := GetStreamUri{
|
|
Xmlns: mediaNamespace,
|
|
Xmlnst: "http://www.onvif.org/ver10/schema",
|
|
ProfileToken: profileToken,
|
|
}
|
|
req.StreamSetup.Stream = "RTP-Unicast"
|
|
req.StreamSetup.Transport.Protocol = "RTSP"
|
|
|
|
var resp GetStreamUriResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, endpoint, "", req, &resp); err != nil {
|
|
return nil, fmt.Errorf("GetStreamUri failed: %w", err)
|
|
}
|
|
|
|
return &MediaURI{
|
|
URI: resp.MediaUri.Uri,
|
|
InvalidAfterConnect: resp.MediaUri.InvalidAfterConnect,
|
|
InvalidAfterReboot: resp.MediaUri.InvalidAfterReboot,
|
|
}, nil
|
|
}
|
|
|
|
// GetSnapshotURI retrieves the snapshot URI for a profile
|
|
func (c *Client) GetSnapshotURI(ctx context.Context, profileToken string) (*MediaURI, error) {
|
|
endpoint := c.mediaEndpoint
|
|
if endpoint == "" {
|
|
endpoint = c.endpoint
|
|
}
|
|
|
|
type GetSnapshotUri struct {
|
|
XMLName xml.Name `xml:"trt:GetSnapshotUri"`
|
|
Xmlns string `xml:"xmlns:trt,attr"`
|
|
ProfileToken string `xml:"trt:ProfileToken"`
|
|
}
|
|
|
|
type GetSnapshotUriResponse struct {
|
|
XMLName xml.Name `xml:"GetSnapshotUriResponse"`
|
|
MediaUri struct {
|
|
Uri string `xml:"Uri"`
|
|
InvalidAfterConnect bool `xml:"InvalidAfterConnect"`
|
|
InvalidAfterReboot bool `xml:"InvalidAfterReboot"`
|
|
Timeout string `xml:"Timeout"`
|
|
} `xml:"MediaUri"`
|
|
}
|
|
|
|
req := GetSnapshotUri{
|
|
Xmlns: mediaNamespace,
|
|
ProfileToken: profileToken,
|
|
}
|
|
|
|
var resp GetSnapshotUriResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, endpoint, "", req, &resp); err != nil {
|
|
return nil, fmt.Errorf("GetSnapshotUri failed: %w", err)
|
|
}
|
|
|
|
return &MediaURI{
|
|
URI: resp.MediaUri.Uri,
|
|
InvalidAfterConnect: resp.MediaUri.InvalidAfterConnect,
|
|
InvalidAfterReboot: resp.MediaUri.InvalidAfterReboot,
|
|
}, nil
|
|
}
|
|
|
|
// GetVideoEncoderConfiguration retrieves video encoder configuration
|
|
func (c *Client) GetVideoEncoderConfiguration(ctx context.Context, configurationToken string) (*VideoEncoderConfiguration, error) {
|
|
endpoint := c.mediaEndpoint
|
|
if endpoint == "" {
|
|
endpoint = c.endpoint
|
|
}
|
|
|
|
type GetVideoEncoderConfiguration struct {
|
|
XMLName xml.Name `xml:"trt:GetVideoEncoderConfiguration"`
|
|
Xmlns string `xml:"xmlns:trt,attr"`
|
|
ConfigurationToken string `xml:"trt:ConfigurationToken"`
|
|
}
|
|
|
|
type GetVideoEncoderConfigurationResponse struct {
|
|
XMLName xml.Name `xml:"GetVideoEncoderConfigurationResponse"`
|
|
Configuration struct {
|
|
Token string `xml:"token,attr"`
|
|
Name string `xml:"Name"`
|
|
UseCount int `xml:"UseCount"`
|
|
Encoding string `xml:"Encoding"`
|
|
Resolution *struct {
|
|
Width int `xml:"Width"`
|
|
Height int `xml:"Height"`
|
|
} `xml:"Resolution"`
|
|
Quality float64 `xml:"Quality"`
|
|
RateControl *struct {
|
|
FrameRateLimit int `xml:"FrameRateLimit"`
|
|
EncodingInterval int `xml:"EncodingInterval"`
|
|
BitrateLimit int `xml:"BitrateLimit"`
|
|
} `xml:"RateControl"`
|
|
} `xml:"Configuration"`
|
|
}
|
|
|
|
req := GetVideoEncoderConfiguration{
|
|
Xmlns: mediaNamespace,
|
|
ConfigurationToken: configurationToken,
|
|
}
|
|
|
|
var resp GetVideoEncoderConfigurationResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, endpoint, "", req, &resp); err != nil {
|
|
return nil, fmt.Errorf("GetVideoEncoderConfiguration failed: %w", err)
|
|
}
|
|
|
|
config := &VideoEncoderConfiguration{
|
|
Token: resp.Configuration.Token,
|
|
Name: resp.Configuration.Name,
|
|
UseCount: resp.Configuration.UseCount,
|
|
Encoding: resp.Configuration.Encoding,
|
|
Quality: resp.Configuration.Quality,
|
|
}
|
|
|
|
if resp.Configuration.Resolution != nil {
|
|
config.Resolution = &VideoResolution{
|
|
Width: resp.Configuration.Resolution.Width,
|
|
Height: resp.Configuration.Resolution.Height,
|
|
}
|
|
}
|
|
|
|
if resp.Configuration.RateControl != nil {
|
|
config.RateControl = &VideoRateControl{
|
|
FrameRateLimit: resp.Configuration.RateControl.FrameRateLimit,
|
|
EncodingInterval: resp.Configuration.RateControl.EncodingInterval,
|
|
BitrateLimit: resp.Configuration.RateControl.BitrateLimit,
|
|
}
|
|
}
|
|
|
|
return config, nil
|
|
}
|
|
|
|
// GetVideoSources retrieves all video sources
|
|
func (c *Client) GetVideoSources(ctx context.Context) ([]*VideoSource, error) {
|
|
endpoint := c.mediaEndpoint
|
|
if endpoint == "" {
|
|
endpoint = c.endpoint
|
|
}
|
|
|
|
type GetVideoSources struct {
|
|
XMLName xml.Name `xml:"trt:GetVideoSources"`
|
|
Xmlns string `xml:"xmlns:trt,attr"`
|
|
}
|
|
|
|
type GetVideoSourcesResponse struct {
|
|
XMLName xml.Name `xml:"GetVideoSourcesResponse"`
|
|
VideoSources []struct {
|
|
Token string `xml:"token,attr"`
|
|
Framerate float64 `xml:"Framerate"`
|
|
Resolution struct {
|
|
Width int `xml:"Width"`
|
|
Height int `xml:"Height"`
|
|
} `xml:"Resolution"`
|
|
} `xml:"VideoSources"`
|
|
}
|
|
|
|
req := GetVideoSources{
|
|
Xmlns: mediaNamespace,
|
|
}
|
|
|
|
var resp GetVideoSourcesResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, endpoint, "", req, &resp); err != nil {
|
|
return nil, fmt.Errorf("GetVideoSources failed: %w", err)
|
|
}
|
|
|
|
sources := make([]*VideoSource, len(resp.VideoSources))
|
|
for i, s := range resp.VideoSources {
|
|
sources[i] = &VideoSource{
|
|
Token: s.Token,
|
|
Framerate: s.Framerate,
|
|
Resolution: &VideoResolution{
|
|
Width: s.Resolution.Width,
|
|
Height: s.Resolution.Height,
|
|
},
|
|
}
|
|
}
|
|
|
|
return sources, nil
|
|
}
|
|
|
|
// GetAudioSources retrieves all audio sources
|
|
func (c *Client) GetAudioSources(ctx context.Context) ([]*AudioSource, error) {
|
|
endpoint := c.mediaEndpoint
|
|
if endpoint == "" {
|
|
endpoint = c.endpoint
|
|
}
|
|
|
|
type GetAudioSources struct {
|
|
XMLName xml.Name `xml:"trt:GetAudioSources"`
|
|
Xmlns string `xml:"xmlns:trt,attr"`
|
|
}
|
|
|
|
type GetAudioSourcesResponse struct {
|
|
XMLName xml.Name `xml:"GetAudioSourcesResponse"`
|
|
AudioSources []struct {
|
|
Token string `xml:"token,attr"`
|
|
Channels int `xml:"Channels"`
|
|
} `xml:"AudioSources"`
|
|
}
|
|
|
|
req := GetAudioSources{
|
|
Xmlns: mediaNamespace,
|
|
}
|
|
|
|
var resp GetAudioSourcesResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, endpoint, "", req, &resp); err != nil {
|
|
return nil, fmt.Errorf("GetAudioSources failed: %w", err)
|
|
}
|
|
|
|
sources := make([]*AudioSource, len(resp.AudioSources))
|
|
for i, s := range resp.AudioSources {
|
|
sources[i] = &AudioSource{
|
|
Token: s.Token,
|
|
Channels: s.Channels,
|
|
}
|
|
}
|
|
|
|
return sources, nil
|
|
}
|
|
|
|
// GetAudioOutputs retrieves all audio outputs
|
|
func (c *Client) GetAudioOutputs(ctx context.Context) ([]*AudioOutput, error) {
|
|
endpoint := c.mediaEndpoint
|
|
if endpoint == "" {
|
|
endpoint = c.endpoint
|
|
}
|
|
|
|
type GetAudioOutputs struct {
|
|
XMLName xml.Name `xml:"trt:GetAudioOutputs"`
|
|
Xmlns string `xml:"xmlns:trt,attr"`
|
|
}
|
|
|
|
type GetAudioOutputsResponse struct {
|
|
XMLName xml.Name `xml:"GetAudioOutputsResponse"`
|
|
AudioOutputs []struct {
|
|
Token string `xml:"token,attr"`
|
|
} `xml:"AudioOutputs"`
|
|
}
|
|
|
|
req := GetAudioOutputs{
|
|
Xmlns: mediaNamespace,
|
|
}
|
|
|
|
var resp GetAudioOutputsResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, endpoint, "", req, &resp); err != nil {
|
|
return nil, fmt.Errorf("GetAudioOutputs failed: %w", err)
|
|
}
|
|
|
|
outputs := make([]*AudioOutput, len(resp.AudioOutputs))
|
|
for i, o := range resp.AudioOutputs {
|
|
outputs[i] = &AudioOutput{
|
|
Token: o.Token,
|
|
}
|
|
}
|
|
|
|
return outputs, nil
|
|
}
|
|
|
|
// CreateProfile creates a new media profile
|
|
func (c *Client) CreateProfile(ctx context.Context, name, token string) (*Profile, error) {
|
|
endpoint := c.mediaEndpoint
|
|
if endpoint == "" {
|
|
endpoint = c.endpoint
|
|
}
|
|
|
|
type CreateProfile struct {
|
|
XMLName xml.Name `xml:"trt:CreateProfile"`
|
|
Xmlns string `xml:"xmlns:trt,attr"`
|
|
Name string `xml:"trt:Name"`
|
|
Token *string `xml:"trt:Token,omitempty"`
|
|
}
|
|
|
|
type CreateProfileResponse struct {
|
|
XMLName xml.Name `xml:"CreateProfileResponse"`
|
|
Profile struct {
|
|
Token string `xml:"token,attr"`
|
|
Name string `xml:"Name"`
|
|
} `xml:"Profile"`
|
|
}
|
|
|
|
req := CreateProfile{
|
|
Xmlns: mediaNamespace,
|
|
Name: name,
|
|
}
|
|
if token != "" {
|
|
req.Token = &token
|
|
}
|
|
|
|
var resp CreateProfileResponse
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, endpoint, "", req, &resp); err != nil {
|
|
return nil, fmt.Errorf("CreateProfile failed: %w", err)
|
|
}
|
|
|
|
return &Profile{
|
|
Token: resp.Profile.Token,
|
|
Name: resp.Profile.Name,
|
|
}, nil
|
|
}
|
|
|
|
// DeleteProfile deletes a media profile
|
|
func (c *Client) DeleteProfile(ctx context.Context, profileToken string) error {
|
|
endpoint := c.mediaEndpoint
|
|
if endpoint == "" {
|
|
endpoint = c.endpoint
|
|
}
|
|
|
|
type DeleteProfile struct {
|
|
XMLName xml.Name `xml:"trt:DeleteProfile"`
|
|
Xmlns string `xml:"xmlns:trt,attr"`
|
|
ProfileToken string `xml:"trt:ProfileToken"`
|
|
}
|
|
|
|
req := DeleteProfile{
|
|
Xmlns: mediaNamespace,
|
|
ProfileToken: profileToken,
|
|
}
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, endpoint, "", req, nil); err != nil {
|
|
return fmt.Errorf("DeleteProfile failed: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// SetVideoEncoderConfiguration sets video encoder configuration
|
|
func (c *Client) SetVideoEncoderConfiguration(ctx context.Context, config *VideoEncoderConfiguration, forcePersistence bool) error {
|
|
endpoint := c.mediaEndpoint
|
|
if endpoint == "" {
|
|
endpoint = c.endpoint
|
|
}
|
|
|
|
type SetVideoEncoderConfiguration struct {
|
|
XMLName xml.Name `xml:"trt:SetVideoEncoderConfiguration"`
|
|
Xmlns string `xml:"xmlns:trt,attr"`
|
|
Xmlnst string `xml:"xmlns:tt,attr"`
|
|
Configuration struct {
|
|
Token string `xml:"token,attr"`
|
|
Name string `xml:"tt:Name"`
|
|
UseCount int `xml:"tt:UseCount"`
|
|
Encoding string `xml:"tt:Encoding"`
|
|
Resolution *struct {
|
|
Width int `xml:"tt:Width"`
|
|
Height int `xml:"tt:Height"`
|
|
} `xml:"tt:Resolution,omitempty"`
|
|
Quality *float64 `xml:"tt:Quality,omitempty"`
|
|
RateControl *struct {
|
|
FrameRateLimit int `xml:"tt:FrameRateLimit"`
|
|
EncodingInterval int `xml:"tt:EncodingInterval"`
|
|
BitrateLimit int `xml:"tt:BitrateLimit"`
|
|
} `xml:"tt:RateControl,omitempty"`
|
|
} `xml:"trt:Configuration"`
|
|
ForcePersistence bool `xml:"trt:ForcePersistence"`
|
|
}
|
|
|
|
req := SetVideoEncoderConfiguration{
|
|
Xmlns: mediaNamespace,
|
|
Xmlnst: "http://www.onvif.org/ver10/schema",
|
|
ForcePersistence: forcePersistence,
|
|
}
|
|
|
|
req.Configuration.Token = config.Token
|
|
req.Configuration.Name = config.Name
|
|
req.Configuration.UseCount = config.UseCount
|
|
req.Configuration.Encoding = config.Encoding
|
|
|
|
if config.Resolution != nil {
|
|
req.Configuration.Resolution = &struct {
|
|
Width int `xml:"tt:Width"`
|
|
Height int `xml:"tt:Height"`
|
|
}{
|
|
Width: config.Resolution.Width,
|
|
Height: config.Resolution.Height,
|
|
}
|
|
}
|
|
|
|
if config.Quality > 0 {
|
|
req.Configuration.Quality = &config.Quality
|
|
}
|
|
|
|
if config.RateControl != nil {
|
|
req.Configuration.RateControl = &struct {
|
|
FrameRateLimit int `xml:"tt:FrameRateLimit"`
|
|
EncodingInterval int `xml:"tt:EncodingInterval"`
|
|
BitrateLimit int `xml:"tt:BitrateLimit"`
|
|
}{
|
|
FrameRateLimit: config.RateControl.FrameRateLimit,
|
|
EncodingInterval: config.RateControl.EncodingInterval,
|
|
BitrateLimit: config.RateControl.BitrateLimit,
|
|
}
|
|
}
|
|
|
|
username, password := c.GetCredentials()
|
|
soapClient := soap.NewClient(c.httpClient, username, password)
|
|
|
|
if err := soapClient.Call(ctx, endpoint, "", req, nil); err != nil {
|
|
return fmt.Errorf("SetVideoEncoderConfiguration failed: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|