Skip to main content
Skip table of contents

EVS Neo [VCon OG]

For controlling the EVS Neo the EVS OpenGateAPI is used. This is a REST Api that contains the baisc elements needed to control a recording.

From the EVS website:
The VIA OpenGate engine offers a complete REST API catalog enabling seamless certified third-party integrations for ingest, asset and metadata management, media transformation, publishing, and playout.

But currently only a subset is implemented, i.e. playout is completely missing.
What the EVS Neo recorder currently does is reading all available recorders from the configuration and create and control a recording.

Setup

The installation of a EVS Neo recorder is done by a dynamic playbook. Below is an example (91_vpms3.evsrecorder.v2.yaml from the project-wdr-phx repository):

YAML
evsrecorder:
  playbook:
    name: evsrecorder
    abbreviation: evsrecorder
  #######################################################
  # Main Chart part                                     #
  # Work in progress                                    #
  #######################################################
  default:
    endpoints:
      http:
        fqdn: "{{ (default_endpoint_scheme + lookup('prepared_config', 'kubernetesPublicEndpoint') + '/' if not lookup('prepared_config', 'kubernetesPublicEndpoint').endswith('/') else '' | string) | urlsplit('hostname') }}"
    helm_chart:
      install: true
      chart_name: recorderevsneo
      chart_subpath:
      chart_folder: VidiControl/Recorders/Evs
      chart_category: VPMS
      chart_namespace: "{{ server_config.system.name }}-vctl"
      chart_instance_name: recorderevsneo
      chart_version: 24.4.257451
      chart_values:
        hull:
          config:
            general:
              globalImageRegistryToFirstRegistrySecretServer: true
              fullnameOverride: recorderevsneo
              data:
                installation:
                  config:
                    customCaCertificates:
{% for key, value in vpms3.global.system.ssl.custom_ca_certs.items() %}
                      {{ key }}: "{{ (value | singleline) + '\n' }}"
{% endfor %}
                endpoints:
                  vidicore:
                    uri:
                      api: "{{ default_endpoint_scheme + lookup('prepared_config', 'kubernetesPublicEndpoint') + '/API'}}"
                  authservice:
                    uri:
                      api: "{{ default_endpoint_scheme + lookup('prepared_config', 'kubernetesPublicEndpoint') + vpms3.authservice.base.default.app_path_authservice }}"
                    auth:
                      token:
                        installationClientId: installerClient
                        installationClientSecret: "{{ vault.vidicontrol.base.default.installer_client_secret }}"
                  configportal:
                    uri:
                      api: "{{ default_endpoint_scheme + lookup('prepared_config', 'kubernetesPublicEndpoint') + vpms3.configportal.base.default.app_path_configportal_api }}"
                      ui: "{{ default_endpoint_scheme + lookup('prepared_config', 'kubernetesPublicEndpoint') + vpms3.configportal.base.default.app_path_configportal_ui }}"
                      notification: "{{ default_endpoint_scheme + lookup('prepared_config', 'kubernetesPublicEndpoint') + vpms3.configportal.base.default.app_path_configportal_notification }}"
                    auth:
                      token:
                        installationClientId: installerClient
                        installationClientSecret: "{{ vault.configportal.base.default.installer_client_secret }}"
                  notification:
                    uri:
                      api: "http://core-services-core-services-noti-api:8080/Platform.Core/Notification/"
                  vidispine:
                    uri:
                      api: "{{ default_endpoint_scheme + lookup('prepared_config', 'kubernetesPublicEndpoint') + '/API/' }}"
                  rule:
                    uri:
                      api: "http://core-services-core-services-rule-api:8080/Platform.Core/Rule/"
            specific:
              ingress:
                controllerClass: "{{ vpms3.global.system.ingress.controllerClass }}"
              registry: "{{ vpms3.global.docker.registry.endpoint }}"
              authService:
                installerClientId: installerClient
                installerClientSecret: "{{ vault.vidicontrol.base.default.installer_client_secret }}"
              recorderevsneo:
                tag: 24.4.257451
                endpoint: "http://recorderevsneo-evsrecorder.phxdev-vctl-vctl:8080"
                devicesettings: '"{\"RECORDER_EVS_NEO_API_URL\":\"https://phx-via-cluster.int.wdr.de\",\"RECORDER_EVS_NEO_API_KEY\":\"dummy\",\"RECORDER_EVS_NEO_INGESTTARGET_ID\":\"dummy\"}"'
              database:
                host: "{{ hostvars['sql-server']['host'] }}"
                port: "{{ hostvars['sql-server']['port'] | default(1433) }}"
                user: "{{ hostvars['sql-server']['admin_user'] }}"
                type: postgres
                connectionstrings:
                  recorderevsneo: "User ID = {{ hostvars['sql-server']['admin_user'] }};Server={{ hostvars['sql-server']['host'] }};Port={{ hostvars['sql-server']['port'] | default(1433) }};Database={{ vpms3.global.system.name | regex_replace('-', '_') }}_recorderevs;Pooling=true;"
                names:
                  recorderevsneo: "{{ vpms3.global.system.name | regex_replace('-', '_') }}_recorderevs"
          objects:
            registry:
              vpms3:
                server: "{{ vpms3.global.docker.registry.endpoint }}"
                username: "{{ vpms3.global.docker.registry.user }}"
                password: "{{ vpms3.global.docker.registry.pass }}"
            deployment:
              vidicontrol-recorderevsneo:
                pod:
                  containers:
                    vidicontrol-recorderevsneo:
                      image:
                        repository: mediacomponent/recorders/recorderevsneo

The versions of the Helm chart and the Docker image must be updated to the currently used versions. Additionally, the device settings must be adapted, mainly the RECORDER_EVS_NEO_API_URL, the RECORDER_EVS_NEO_API_KEY and the RECORDER_EVS_NEO_INGESTTARGET_ID.
The Api Key can be created on the Account Settings Page of the VIA MAP UI.


For installing the recorder, the preferred installation method with the tag “evsrecorder” can be used, i.e.

BASH
./prepared.sh --log=vvv --tags=evsrecorder

Customize config after installation

Workflow

When a recording is started a VidiFlow workflow will be triggered.
This workflow must be created, named 'WF_EvsRecording' and have 'ItemId' and 'RecordingSession' as parameters (type string). Workflow name and version can be changed via the VidiControl Configuration Tool.
The version of the workflow must correspond to the version listed in the event 'RecorderEvsNeo.startWorkflow'.
The module executes a periodic status check of the EVS server and, if necessary, sets the VidiControl device status to online or offline.

Capability

EvsTargets must be added to the recorder capability after installation.
Add a field of type 'enum' with name EvsTarget to the input of the Capability Content.
The TargetRef values (Guid) of the targets from the EVS system, which should be available for selection in VidiControl, are used as enum values.
This may also be possible with the Config UI.
Example:

JSON
"input": {
        "name": {
            "type": "string",
            "optional": "false"
        },
        "EvsTarget": {
            "label": "EVS Targets",
            "hint": "Select an option",
            "type": "enum",
            "items": {
                "item0": {
                    "label": "Target1",
                    "value": "087dfs6b-987df987sd-984375f"
                },
                "item1": {
                    "label": "Target2",
                    "value": "087dfs6b-98sdaddsd-98dsddd",
                    "default": true
                }
            }
        }
    }

Configuration

The Guid for the default target (e.g. for crash record; intial value in DeviceConfiguration:DeviceSettings RECORDER_EVS_NEO_INGESTTARGET_ID) is saved as EvsDefaultIngestTargetId in the recoder config table and can be changed via the Config UI for each Pod.

The timezone Id of the EVSApi (intial value in DeviceConfiguration:DeviceSettings 'RECORDER_EVS_NEO_API_TIMEZONE') is saved as EvsTimezone in the recoder config table and can be changed via the Config UI for each Pod.
The Timezone IDs are operating system dependent. To get these IDs, start the recorder once without RECORDER_EVS_NEO_API_TIMEZONE. Then it should output a warning in the logfile 'Couldn't load timezone info' and below it a list of all available timezones in the format '<TimezoneId>; <TimezoneName>'.
Example: On a windows system the timezone Id for London is 'GMT Standard Time', on Linux it is 'Europe/London'. (List of IANA timezone Ids for Linux)

Additional config values

Config value

Type

Comment

VIDICONTROL_DATABASE_CONNECTION_STRING

string

VIDICONTROL_DATABASE_PASSWORD

string

VIDICONTROL_IDSALT

string

VIDICONTROL_SITEID

string

site id (alphanumeric)

RECORDER_EVS_NEO_DATABASE_CONNECTION_STRING

string

RECORDER_EVS_NEO_DATABASE_PASSWORD

string

RECORDER_EVS_NEO_INGESTTARGET_ID

string

(DeviceConfiguration:DeviceSettings) default target

RECORDER_EVS_NEO_API_KEY

string

(DeviceConfiguration:DeviceSettings)

RECORDER_EVS_NEO_API_URL

string

(DeviceConfiguration:DeviceSettings)

RECORDER_EVS_NEO_API_TIMEZONE

string

(DeviceConfiguration:DeviceSettings)

RECORDER_EVS_NEO_API_STATUS_ONLINE

string

(DeviceConfiguration:DeviceSettings) comma-separated list of the EVS server status values ​​that mean 'online' for the device, e.g. 'CONNECTED,SomeOtherValue'

RECORDER_EVS_NEO_API_STATUS_REC_UNAVAILABLE

string

(DeviceConfiguration:DeviceSettings) comma-separated list of the EVS recorder status values ​​that mean 'offline' for the device, e.g. 'in error,anotherValue'

RECORDER_EVS_NEO_API_STATUS_CHECK_PERIOD_IN_S

int

(DeviceConfiguration:DeviceSettings) Interval in seconds in which the EVS recorder status check is executed, default is -1. If <=0 status check is disabled.

RECORDER_EVS_NEO_DISABLE_ALL_CHECK_COUNT

int

(DeviceConfiguration:DeviceSettings) Number of failed status checks after which all devices are set to offline, default is 0

Config for VidiControl initialization (Device, Capabilities, Events)

Values for Capabilities and Events are fixed, values in DeviceConfiguration are system specific

JSON
  "DeviceConfiguration": {
    "DeviceName": "RecorderEvsNeo",
    "Uri": "<http://localhost:5187>",
    "DeviceSettings": "{\"RECORDER_EVS_NEO_API_URL\":\"the-EVS-API-Endpoint\",\"RECORDER_EVS_NEO_API_KEY\":\"the-APIKey-for-EVS-API\",\"RECORDER_EVS_NEO_INGESTTARGET_ID\":\"the-default-recording-target-Id\",\"RECORDER_EVS_NEO_API_TIMEZONE\":\"GMT Standard Time\",\"RECORDER_EVS_NEO_API_STATUS_ONLINE\":\"CONNECTED\",\"RECORDER_EVS_NEO_API_STATUS_CHECK_PERIOD_IN_S\":45,\"RECORDER_EVS_NEO_API_STATUS_REC_UNAVAILABLE\":\"in error\"}",
    "CapabilityGroup": "RecorderEvsNeoGroup"
  },
  "Capability": [
    {
      "Content": "{\"action\":\"Record\",\"input\":{\"name\":{\"type\":\"string\",\"optional\":\"false\"}},\"properties\":{\"nonBlockingProvisioningTime\":{\"type\":\"integer\",\"kind\":\"fix\"}},\"events\":[\"RecorderEvsNeo.startWorkflow\", \"RecorderEvsNeo.recordingFailed\", \"RecorderEvsNeo.recordingStarted\", \"RecorderEvsNeo.recordingFinished\", \"RecorderEvsNeo.recordingScheduled\",\"RecorderEvsNeo.recordingUpdateFailed\"]}",
      "NeedsStopCommand": true,
      "CapabilityType": 0,
      "DefaultConfig": "{\"nonBlockingProvisioningTime\":10}"
    }
  ],
  "EventType": [
    {
      "Name": "RecorderEvsNeo.startWorkflow",
      "HandleCustomerSpecific": false,
      "Description": "",
      "Content": "[{\"action\": \"startWorkflow\",\"input\": {\"Name\": \"WF_EvsRecording\",\"Version\": \"1.Latest\",\"Data\": {\"Parameters\": [{\"Name\": \"RecordingSession\",\"Value\": \"{-{Placeholder_RecordingsSession}-}\",\"Type\": \"string\"}, {\"Name\": \"ItemId\",\"Value\": \"{-{Placeholder_VCItemId}-}\",\"Type\": \"string\"}],\"Metadata\": null,\"Priority\": null}}}]"
    },
    {
      "Name": "RecorderEvsNeo.recordingStarted",
      "HandleCustomerSpecific": false,
      "Description": "",
      "Content": "[{\"action\":\"notifyClient\",\"input\":{\"TimeStamp\":\"{-{Placeholder_TimeStamp}-}\",\"ChunkId\":\"{-{Placeholder_ExternalChunkId}-}\",\"UpdateNeeded\":false,\"MessageType\":\"RecorderEvsNeo.recordingStarted\",\"Emitter\":\"{-{Placeholder_Emitter}-}\",\"Severity\":\"Information\",\"Message\":[{\"Lang\":\"en_US\",\"Text\":\"Recording started.\"},{\"Lang\":\"de_DE\",\"Text\":\"Aufnahme gestartet.\"}]}}]"
    },
    {
      "Name": "RecorderEvsNeo.recordingFinished",
      "HandleCustomerSpecific": false,
      "Description": "",
      "Content": "[{\"action\":\"notifyClient\",\"input\":{\"TimeStamp\":\"{-{Placeholder_TimeStamp}-}\",\"ChunkId\":\"{-{Placeholder_ExternalChunkId}-}\",\"UpdateNeeded\":false,\"MessageType\":\"RecorderEvsNeo.recordingFinished\",\"Emitter\":\"{-{Placeholder_Emitter}-}\",\"Severity\":\"Information\",\"Message\":[{\"Lang\":\"en_US\",\"Text\":\"Recording finished.\"},{\"Lang\":\"de_DE\",\"Text\":\"Aufnahme beendet.\"}]}}]"
    },
    {
      "Name": "RecorderEvsNeo.recordingFailed",
      "HandleCustomerSpecific": false,
      "Description": "",
      "Content": "[{\"action\":\"notifyClient\",\"input\":{\"TimeStamp\":\"{-{Placeholder_TimeStamp}-}\",\"ChunkId\":\"{-{Placeholder_ExternalChunkId}-}\",\"UpdateNeeded\":false,\"MessageType\":\"RecorderEvsNeo.recordingFailed\",\"Emitter\":\"{-{Placeholder_Emitter}-}\",\"Severity\":\"Error\",\"Message\":[{\"Lang\":\"en_US\",\"Text\":\"Recording failed.\"},{\"Lang\":\"de_DE\",\"Text\":\"Aufnahme gescheitert.\"}]}}]"
    },
    {
      "Name": "RecorderEvsNeo.recordingScheduled",
      "HandleCustomerSpecific": false,
      "Description": "",
      "Content": "[{\"action\":\"notifyClient\",\"input\":{\"TimeStamp\":\"{-{Placeholder_TimeStamp}-}\",\"ChunkId\":\"{-{Placeholder_ExternalChunkId}-}\",\"UpdateNeeded\":false,\"MessageType\":\"RecorderEvsNeo.recordingScheduled\",\"Emitter\":\"{-{Placeholder_Emitter}-}\",\"Severity\":\"Information\",\"Message\":[{\"Lang\":\"en_US\",\"Text\":\"Recording scheduled.\"},{\"Lang\":\"de_DE\",\"Text\":\"Aufnahme geplant.\"}]}}]"
    },
    {
      "Name": "RecorderEvsNeo.recordingUpdateFailed",
      "HandleCustomerSpecific": false,
      "Description": "",
      "Content": "[{\"action\":\"notifyClient\",\"input\":{\"TimeStamp\":\"{-{Placeholder_TimeStamp}-}\",\"ChunkId\":\"{-{Placeholder_ExternalChunkId}-}\",\"UpdateNeeded\":false,\"MessageType\":\"RecorderEvsNeo.recordingUpdateFailed\",\"Emitter\":\"{-{Placeholder_Emitter}-}\",\"Severity\":\"Warning\",\"Message\":[{\"Lang\":\"en_US\",\"Text\":\"Recording update failed.\"},{\"Lang\":\"de_DE\",\"Text\":\"Update der Aufnahme fehlgeschlagen.\"}]}}]"
    }
  ]

Device

Requires a ConnectionInfo with EVS server Id (RecorderRef)

JSON
{
    "RecorderRef": "eccaa4ff-7371-4ffe-834e-963a524c42a6"
}

Capability

Requires a Content with an input parameter 'name'

JSON
{
    "action": "Record",
    "input": {
        "name": {
            "type": "string",
            "optional": "false"
        }
    },
    "output": {
    },
    "properties": {
        "preroll": {
            "type": "integer",
            "kind": "fix"
        }
    },
    "events": ["RecorderEvsNeo.fileCreated", "RecorderEvsNeo.recordingFailed", "RecorderEvsNeo.recordingStarted", "RecorderEvsNeo.recordingFinished"]
}

EventType

Requires an EventType with action 'startWorkflow' and placeholder 'Placeholder_RecordingsSession' for the EVS RecordingsSession data

JSON
[{"action": "startWorkflow","input": {"Name": "WF_EvsRecording","Version": "latest","Data": {"Parameters": [{"Name": "RecordingSession","Value": "{{Placeholder_RecordingsSession}}","Type": "string"}, {"Name": "Item","Value": "{{Placeholder_VCItemId}}","Type": "string"}],"Metadata": null,"Priority": null}}}]

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.