Quantel (sQ Servers) [VCon OG]
RecorderQuantel is a recorder using the DirectConnect API (v2.6.21) to trigger recordings and create clips on Grassvalley's sQ servers. On starting a recording, it is assigned a clipId and metadata 'owner' with a defined ownerPrefix. The latter can be used (and is used at TV2 and HSB) by a customjob to transfer the clip to VidiCore avoiding duplicate creation.
Setup
The installation of a RecorderQuantel is done by a dynamic playbook. Below is an example (91_vpms3.tv2recorderquantel.v2.yaml from the tv2-prod inventory of the project-tv2 repository):
tv2recorderquantel:
playbook:
name: tv2recorderquantel
abbreviation: tv2recorderquantel
#######################################################
# 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: tv2recorderquantel
chart_subpath:
chart_folder: VidiControl/Recorders/Quantel
chart_category: VPMS
chart_namespace: "{{ server_config.system.name }}-vctl"
chart_instance_name: tv2recorderquantel
chart_version: 24.2.246644
chart_values:
hull:
config:
general:
globalImageRegistryToFirstRegistrySecretServer: true
fullnameOverride: tv2recorderquantel
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 }}"
recorderquantel:
tag: 24.2.246644
devicesettings: "{\\\"QUANTEL_HTTP_CONNECTIONSTRING\\\":\\\"http://10.22.60.11/\\\",\\\"QUANTEL_WS_CONNECTIONSTRING\\\":\\\"ws://10.22.60.11/websocket/\\\",\\\"QUANTEL_MAX_RECORDING_HOURS\\\":\\\"12\\\",\\\"QUANTEL_RECORDER_ID\\\":\\\"RecA\\\",\\\"QUANTEL_TIMEZONE\\\":\\\"UTC\\\",\\\"QUANTEL_CLIP_METADATA_FIELDS_FOR_CHUNKID\\\":\\\"owner\\\",\\\"QUANTEL_STATUS_ONLINE\\\":\\\"Idle,Record\\\",\\\"QUANTEL_VERSION\\\":\\\"V2.6.21/001\\\",\\\"QUANTEL_STATUS_CHECK_PERIOD_IN_S\\\":\\\"45\\\",\\\"QUANTEL_TCSOURCE\\\":\\\"ref\\\"}"
devicename: "RecorderQuantel_5081"
recorderquantelgroup: "RecorderQuantelGroup"
database:
host: "{{ hostvars['sql-server']['host'] }}"
port: "{{ hostvars['sql-server']['port'] | default(1433) }}"
user: "{{ hostvars['sql-server']['admin_user'] }}"
type: postgres
names:
recorderquantel: "{{ vpms3.global.system.name | regex_replace('-', '_') }}_vidicontrol_recorderquantel"
connectionstrings:
recorderquantel: "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('-', '_') }}_vidicontrol_recorderquantel;Integrated Security=true;Pooling=true;"
objects:
registry:
vpms3:
server: "{{ vpms3.global.docker.registry.endpoint }}"
username: "{{ vpms3.global.docker.registry.user }}"
password: "{{ vpms3.global.docker.registry.pass }}"
service:
recorderquantel:
selector:
app.kubernetes.io/component: vidicontrol-recorderquantel
app.kubernetes.io/instance: tv2recorderquantel
app.kubernetes.io/name: tv2recorderquantel
deployment:
vidicontrol-recorderquantel:
replicas: 0
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 QUANTEL_HTTP_CONNECTIONSTRING and QUANTEL_WS_CONNECTIONSTRING.
For installing the recorder, the preferred installation method with the tag “tv2recorderquantel” can be used, i.e.
./prepared.sh --log=vvv --tags=tv2recorderquantel
Customize config after installation
Workflow
By default no workflow is configured for a recording start. If neccesary see i.e.
Flics Ingest [VCon OG] | Workflow
how to trigger and configure a VidiFlow workflow.
Capability
Source and Template are read from the FLICS cluster on module start. When available in the front end the input can be switched to the DynamicEnumValue entries Template and Source
Example:
"input": {
"Source": {
"defaultValue": null,
"externalDataIdentifier": "",
"hint": "[{\"Lang\":\"en_US\",\"Text\":\"The SRT Source\"},{\"Lang\":\"de_DE\",\"Text\":\"Die SRT Quelle\"}]",
"items": {
"item0": {
"default": true,
"label": "SRT1",
"value": "SRT1"
},
"item1": {
"default": false,
"label": "Zuspieler2",
"value": "Zuspieler2"
},
"item2": {
"default": false,
"label": "SRT",
"value": "SRT"
},
"item3": {
"default": false,
"label": "DJSRT",
"value": "DJSRT"
}
},
"label": "[{\"Lang\":\"en_US\",\"Text\":\"SRT Source\"},{\"Lang\":\"de_DE\",\"Text\":\"SRT Quelle\"}]",
"optional": null,
"type": "enum"
},
"Template": {
"defaultValue": null,
"externalDataIdentifier": "",
"hint": "[{\"Lang\":\"en_US\",\"Text\":\"The Target Template\"},{\"Lang\":\"de_DE\",\"Text\":\"Das Ziel Template\"}]",
"items": {
"item0": {
"default": true,
"label": "Live XDCAM GROWING",
"value": "586a2314-34f9-4d76-b268-d5873a611695"
},
"item1": {
"default": false,
"label": "Live XDCAM GROWING HISCALE",
"value": "ebecb908-f9a6-4f2c-9a77-92132e37dcfe"
},
"item2": {
"default": false,
"label": "Live XRDD25 GROWING",
"value": "f12a8bab-2b0f-41cf-9d71-90ee599c6848"
},
"item3": {
"default": false,
"label": "LiveSD Template",
"value": "fa18fe20-2744-4d71-8d22-5b8d4e0a6a6f"
},
"item4": {
"default": false,
"label": "RDD25 50p",
"value": "e3725ca1-b2ce-4c3e-82ad-1a2b9029cab2"
},
"item5": {
"default": false,
"label": "RDD25 Growing",
"value": "f63f598c-3517-4c63-add8-d3882df7f46f"
}
},
"label": "[{\"Lang\":\"en_US\",\"Text\":\"Target Template\"},{\"Lang\":\"de_DE\",\"Text\":\"Ziel Template\"}]",
"optional": null,
"type": "enum"
}
}
Configuration
Config value | Type | Comment |
|---|---|---|
VIDICONTROL_DATABASE_CONNECTION_STRING | string |
|
VIDICONTROL_DATABASE_PASSWORD | string |
|
VIDICONTROL_IDSALT | string | |
VIDICONTROL_SITEID | string | site id (alphanumeric) |
RECORDER_QUANTEL_DATABASE_CONNECTION_STRING | string |
|
RECORDER_QUANTEL_DATABASE_PASSWORD | string |
|
QUANTEL_VERSION | string | (DeviceConfiguration:DeviceSettings) |
QUANTEL_HTTP_CONNECTIONSTRING | string | (DeviceConfiguration:DeviceSettings) |
QUANTEL_WS_CONNECTIONSTRING | string | (DeviceConfiguration:DeviceSettings) |
QUANTEL_CLIP_METADATA_FIELDS_FOR_CHUNKID | string | (DeviceConfiguration:DeviceSettings) Comma-separated list of clip metadata fields the vidicontrol-id should be written to |
QUANTEL_STATUS_CHECK_PERIOD_IN_S | string | (DeviceConfiguration:DeviceSettings) |
QUANTEL_MAX_RECORDING_HOURS | string | (DeviceConfiguration:DeviceSettings) Maximal length of a recording |
QUANTEL_TIMEZONE | string | (DeviceConfiguration:DeviceSettings) Time zone of the Quantel server (required to calculate starttime) |
QUANTEL_TCSOURCE | string | (DeviceConfiguration:DeviceSettings) 'ref' for system reference timecode or 'port' for port timecode (required to set starttime) |
QUANTEL_SWITCHTOBLACK_DEVICEID | string | (DeviceConfiguration:DeviceSettings) (internal) deviceid of the sole router in the system |
QUANTEL_BLACK_PORTID | string | (DeviceConfiguration:DeviceSettings) (internal) inportid of the 'black' port to be switched to after stopping the recording |
QUANTEL_CRASH_RECORD_DELTA_S | string | (DeviceConfiguration:DeviceSettings) time period in sec. after now() within which a recording will be started immediately (crash) |
The Timezone IDs are operating system dependent. To get these IDs, start the recorder once without QUANTEL_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)
Config for VidiControl initialization (Device, Capabilities, Events)
"DeviceConfiguration": {
"DeviceName": "RecorderQuantel",
"Uri": "",
"DeviceSettings": "{\"QUANTEL_VERSION\":\"V2.6.21/001\",\"QUANTEL_HTTP_CONNECTIONSTRING\":\"<http://<Url> of sQ>/\", \"QUANTEL_WS_CONNECTIONSTRING\":\"ws://<Url of sQ>/websocket/\",\"QUANTEL_CLIP_METADATA_FIELDS_FOR_CHUNKID\":\"owner,description\",\"QUANTEL_TIMEZONE\":\"UTC\",\"QUANTEL_TCSOURCE\":\"ref\"}",
"CapabilityGroup": "RecorderQuantelGroup"
},
"Capability": [
{
"Content": "{\"action\":\"Record\", \"properties\":{\"blockingProvisioningTime\":{\"type\":\"integer\",\"kind\":\"fix\"}}, \"events\":[\"RecorderQuantel.recordingFailed\", \"RecorderQuantel.recordingStarted\", \"RecorderQuantel.recordingFinished\", \"RecorderQuantel.updateFinished\", \"RecorderQuantel.updateFailed\"]}",
"NeedsStopCommand": true,
"CapabilityType": 0,
"DefaultConfig": "{\"blockingProvisioningTime\":10}"
}
],
"EventType": [
{
"Name": "RecorderQuantel.recordingStarted",
"HandleCustomerSpecific": false,
"Description": "",
"Content": "[{\"action\":\"notifyClient\",\"input\":{\"TimeStamp\":\"{-{Placeholder_TimeStamp}-}\",\"ChunkId\":\"{-{Placeholder_ExternalChunkId}-}\",\"UpdateNeeded\":false,\"MessageType\":\"RecordeQuantel.recordingStarted\",\"Emitter\":\"{-{Placeholder_Emitter}-}\",\"Severity\":\"Information\",\"Message\":[{\"Lang\":\"en_US\",\"Text\":\"Recording started.\"},{\"Lang\":\"de_DE\",\"Text\":\"Aufnahme gestartet.\"}]}}]"
},
{
"Name": "RecorderQuantel.recordingFinished",
"HandleCustomerSpecific": false,
"Description": "",
"Content": "[{\"action\":\"notifyClient\",\"input\":{\"TimeStamp\":\"{-{Placeholder_TimeStamp}-}\",\"ChunkId\":\"{-{Placeholder_ExternalChunkId}-}\",\"UpdateNeeded\":false,\"MessageType\":\"RecorderQuantel.recordingFinished\",\"Emitter\":\"{-{Placeholder_Emitter}-}\",\"Severity\":\"Information\",\"Message\":[{\"Lang\":\"en_US\",\"Text\":\"Recording finished.\"},{\"Lang\":\"de_DE\",\"Text\":\"Aufnahme beendet.\"}]}}]"
},
{
"Name": "RecorderQuantel.RecordingFailed",
"HandleCustomerSpecific": false,
"Description": "",
"Content": "[{\"action\":\"notifyClient\",\"input\":{\"TimeStamp\":\"{-{Placeholder_TimeStamp}-}\",\"ChunkId\":\"{-{Placeholder_ExternalChunkId}-}\",\"UpdateNeeded\":false,\"MessageType\":\"RecorderQuantel.recordingFailed\",\"Emitter\":\"{-{Placeholder_Emitter}-}\",\"Severity\":\"Information\",\"Message\":[{\"Lang\":\"en_US\",\"Text\":\"Recording failed.\"},{\"Lang\":\"de_DE\",\"Text\":\"Aufnahme gescheitert.\"}]}}]"
},
{
"Name": "RecorderQuantel.updateFailed",
"HandleCustomerSpecific": false,
"Description": "",
"Content": "[{\"action\":\"notifyClient\",\"input\":{\"TimeStamp\":\"{-{Placeholder_TimeStamp}-}\",\"ChunkId\":\"{-{Placeholder_ExternalChunkId}-}\",\"UpdateNeeded\":false,\"MessageType\":\"RecorderQuantel.updateFailed\",\"Emitter\":\"{-{Placeholder_Emitter}-}\",\"Severity\":\"Information\",\"Message\":[{\"Lang\":\"en_US\",\"Text\":\"Update failed.\"},{\"Lang\":\"de_DE\",\"Text\":\"Update fehlgeschlagen.\"}]}}]"
},
{
"Name": "RecorderQuantel.updateFinished",
"HandleCustomerSpecific": false,
"Description": "",
"Content": "[{\"action\":\"notifyClient\",\"input\":{\"TimeStamp\":\"{-{Placeholder_TimeStamp}-}\",\"ChunkId\":\"{-{Placeholder_ExternalChunkId}-}\",\"UpdateNeeded\":false,\"MessageType\":\"RecorderQuantel.updateFinished\",\"Emitter\":\"{-{Placeholder_Emitter}-}\",\"Severity\":\"Information\",\"Message\":[{\"Lang\":\"en_US\",\"Text\":\"Update finished.\"},{\"Lang\":\"de_DE\",\"Text\":\"Update erfolgreich.\"}]}}]"
}
]