diff --git a/docs/data-sources/live_channels.md b/docs/data-sources/live_channels.md new file mode 100644 index 00000000000..64bec001429 --- /dev/null +++ b/docs/data-sources/live_channels.md @@ -0,0 +1,392 @@ +--- +subcategory: "Live" +layout: "huaweicloud" +page_title: "HuaweiCloud: huaweicloud_live_channels" +description: |- + Use this data source to get the list of Live channels within HuaweiCloud. +--- + +# huaweicloud_live_channels + +Use this data source to get the list of Live channels within HuaweiCloud. + +## Example Usage + +```hcl +data "huaweicloud_live_channels" "test" { +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String) Specifies the region in which to query the resource. + If omitted, the provider-level region will be used. + +* `domain_name` - (Optional, String) Specifies the channel streaming domain name. + +* `app_name` - (Optional, String) Specifies the group name or application name. + +* `channel_id` - (Optional, String) Specifies the channel ID. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The data source ID. + +* `channels` - The channel information. + + The [channels](#channels_struct) structure is documented below. + + +The `channels` block supports: + +* `domain_name` - The channel streaming domain name. + +* `app_name` - The group name or application name. + +* `state` - The channel status. Valid values are: + + **ON**: After a channel is delivered, functions such as stream pull, transcoding, and recording are automatically enabled. + + **OFF**: Only the channel information is saved but the channel is not started. + +* `input` - The channel input information. + The [input](#LiveChannel_Input) structure is documented below. + +* `record_settings` - The configuration for replaying a recording. + The [record_settings](#LiveChannel_RecordSettings) structure is documented below. + +* `endpoints` - The channel outflow information. + The [endpoints](#LiveChannel_Endpoints) structure is documented below. + +* `encoder_settings_expand` - The audio output configuration. + The [encoder_settings_expand](#LiveChannel_EncoderSettingsExpand) structure is documented below. + +* `encoder_settings` - The transcoding template configuration. + The [encoder_settings](#LiveChannel_EncoderSettings) structure is documented below. + +* `name` - The channel name. The name can be duplicated. + +* `id` - The channel ID. + + +The `input` block supports: + +* `input_protocol` - The channel input protocol. Valid values are: + + **FLV_PULL**. + + **RTMP_PUSH**. + + **HLS_PULL**. + + **SRT_PULL**. + + **SRT_PUSH**. + +* `sources` - The channel main source stream information. + The [sources](#LiveChannel_Sources) structure is documented below. + +* `secondary_sources` - The prepared stream array. + The [secondary_sources](#LiveChannel_SecondarySources) structure is documented below. + +* `failover_conditions` - The configuration of switching between primary and backup audio and video stream URLs. + The [failover_conditions](#LiveChannel_FailoverConditions) structure is documented below. + +* `max_bandwidth_limit` - The maximum bandwidth that needs to be configured when the inbound protocol is **HLS_PULL**. + The unit is **bps**. + +* `ip_port_mode` - The IP port mode. + +* `ip_whitelist` - The IP whitelist when protocol is **SRT_PUSH**. + +* `scte35_source` - The advertisement scte35 signal source. + +* `ad_triggers` - The ad trigger configuration list. Valid Values are: + + **Splice insert**. + + **Provider advertisement**. + + **Distributor advertisement**. + + **Provider placement opportunity**. + + **Distributor placement opportunity**. + +* `audio_selectors` - The audio selector configuration. + The [audio_selectors](#LiveChannel_AudioSelectors) structure is documented below. + + +The `sources` block supports: + +* `url` - The channel source stream URL, used for external streaming. + +* `bitrate` - The bitrate. The unit is **bps**. + +* `width` - The resolution corresponds to the width value. + +* `height` - The resolution corresponds to the high value. + +* `enable_snapshot` - Whether to use this stream to take screenshots. + +* `bitrate_for3u8` - Whether to use bitrate to fix the bitrate. + +* `passphrase` - The encrypted information when the protocol is **SRT_PUSH**. + +* `backup_urls` - The list of backup stream addresses. + +* `stream_id` - The stream ID of the stream pull address when the channel type is **SRT_PULL**. + +* `latency` - The streaming delay when the channel type is **SRT_PULL**. + + +The `secondary_sources` block supports: + +* `url` - The channel source stream URL, used for external streaming. + +* `bitrate` - The bitrate. The unit is **bps**. + +* `width` - The resolution corresponds to the width value. + +* `height` - The resolution corresponds to the high value. + +* `bitrate_for3u8` - Whether to use bitrate to fix the bitrate. + +* `passphrase` - The encrypted information when the protocol is **SRT_PUSH**. + +* `backup_urls` - The list of backup stream addresses. + +* `stream_id` - The stream ID of the stream pull address when the channel type is **SRT_PULL**. + +* `latency` - The streaming delay when the channel type is **SRT_PULL**. + + +The `failover_conditions` block supports: + +* `input_loss_threshold_msec` - The duration threshold of inflow stop. The unit is millisecond. + +* `input_preference` - The input preference type. Valid values are: + + **PRIMARY**: The main incoming URL is the first priority. + + **EQUAL**: Equal switching between primary and backup URLs. + + +The `audio_selectors` block supports: + +* `name` - The name of the audio selector. + +* `selector_settings` - The audio selector configuration. + The [selector_settings](#LiveChannel_SelectorSettings) structure is documented below. + + +The `selector_settings` block supports: + +* `audio_language_selection` - The language selector configuration. + The [audio_language_selection](#LiveChannel_AudioLanguageSelection) structure is documented below. + +* `audio_pid_selection` - The PID selector configuration. + The [audio_pid_selection](#LiveChannel_AudioPidSelection) structure is documented below. + +* `audio_hls_selection` - The HLS selector configuration. + The [audio_hls_selection](#LiveChannel_AudioHlsSelection) structure is documented below. + + +The `audio_language_selection` block supports: + +* `language_code` - The language abbreviation. Supports `2` or `3` lowercase letter language codes. + +* `language_selection_policy` - The language output strategy. Valid values are: + + **LOOSE**: Loose matching. For example, "eng" will prioritize matching tracks with English as the language in the + source stream. If no match is found, the track with the smallest PID will be selected. + + **STRICT**: Strict matching. For example, "eng" will strictly match the audio track in the source stream whose + language is English. If no match is found, the media live broadcast service will automatically fill in a silent + segment. When the terminal uses this audio selector to play the video, it will be played silently. + + +The `audio_pid_selection` block supports: + +* `pid` - The value of PID. + + +The `audio_hls_selection` block supports: + +* `name` - The HLS audio selector name. + +* `group_id` - The HLS audio selector gid. + + +The `record_settings` block supports: + +* `rollingbuffer_duration` - The maximum playback recording time. During this time period, the recording will continue. + The unit is second. + + +The `endpoints` block supports: + +* `hls_package` - The HLS packaging information. + The [hls_package](#LiveChannel_HlsPackage) structure is documented below. + +* `dash_package` - The DASH packaging information. + The [dash_package](#LiveChannel_DashPackage) structure is documented below. + +* `mss_package` - The MSS packaging information. + The [mss_package](#LiveChannel_MssPackage) structure is documented below. + + +The `hls_package` block supports: + +* `url` - The customer-defined streaming address, including method, domain name, and path. + +* `stream_selection` - The stream selection. Filter out the specified range of streams from the full stream. + The [stream_selection](#LiveChannel_StreamSelection) structure is documented below. + +* `hls_version` - The HLS version. + +* `segment_duration_seconds` - The duration of the channel output segment. The unit is second. + +* `playlist_window_seconds` - The window length of the channel live broadcast return shard. The unit is second. + +* `encryption` - The encrypted information. + The [encryption](#LiveChannel_Encryption) structure is documented below. + +* `request_args` - The play related configuration. + The [request_args](#LiveChannel_RequestArgs) structure is documented below. + +* `ad_marker` - The advertising marker. + + +The `dash_package` block supports: + +* `url` - The customer-defined streaming address, including method, domain name, and path. + +* `stream_selection` - The stream selection. Filter out the specified range of streams from the full stream. + The [stream_selection](#LiveChannel_StreamSelection) structure is documented below. + +* `segment_duration_seconds` - The duration of the channel output segment. The unit is second. + +* `playlist_window_seconds` - The window length of the channel live broadcast return shard. The unit is second. + +* `encryption` - The encrypted information. + The [encryption](#LiveChannel_Encryption) structure is documented below. + +* `request_args` - The play related configuration. + The [request_args](#LiveChannel_RequestArgs) structure is documented below. + +* `ad_marker` - The advertising marker. + + +The `mss_package` block supports: + +* `url` - The customer-defined streaming address, including method, domain name, and path. + +* `stream_selection` - The stream selection. Filter out the specified range of streams from the full stream. + The [stream_selection](#LiveChannel_StreamSelection) structure is documented below. + +* `segment_duration_seconds` - The duration of the channel output segment. The unit is second. + +* `playlist_window_seconds` - The window length of the channel live broadcast return shard. The unit is second. + +* `encryption` - The encrypted information. + The [encryption](#LiveChannel_Encryption) structure is documented below. + +* `delay_segment` - The delayed playback time. The unit is second. + +* `request_args` - The play related configuration. + The [request_args](#LiveChannel_RequestArgs) structure is documented below. + + +The `stream_selection` block supports: + +* `key` - The key used for bitrate filtering in streaming URLs. + +* `max_bandwidth` - The maximum code rate. The unit is bps. + +* `min_bandwidth` - The minimum code rate. The unit is bps. + + +The `encryption` block supports: + +* `level` - The level. Valid values are: + + **content**: One channel corresponds to one key. + + **profile**: One code rate corresponds to one key. + +* `resource_id` - The customer-generated DRM content ID. + +* `system_ids` - The system ID enumeration values. Valid values are **FairPlay** (HLS), + **Widevine** (DASH), **PlayReady** (DASH), and **PlayReady** (MSS). + +* `url` - The DRM address of the key. + +* `speke_version` - The DRM spec version number. + +* `request_mode` - The request mode. Valid values are: + + **direct_http**: HTTP(S) direct access to DRM. + + **functiongraph_proxy**: FunctionGraph proxy access to DRM. + +* `http_headers` - The authentication information that needs to be added to the DRM request header. + The [http_headers](#LiveChannel_HttpHeader) structure is documented below. + +* `urn` - The URN of the function graph. + + +The `http_headers` block supports: + +* `key` - The key field name in the request header. + +* `value` - The value corresponding to the key in the request header. + + +The `request_args` block supports: + +* `record` - The recording and playback related configuration. + The [record](#LiveChannel_RequestArgsRecord) structure is documented below. + +* `timeshift` - The time-shift playback configuration. + The [timeshift](#LiveChannel_RequestArgsTimeShift) structure is documented below. + +* `live` - The live broadcast configuration. + The [live](#LiveChannel_RequestArgsLive) structure is documented below. + + +The `record` block supports: + +* `start_time` - The start time. + +* `end_time` - The end time. + +* `format` - The format. + +* `unit` - The unit. + + +The `timeshift` block supports: + +* `back_time` - The time shift duration field name. + +* `unit` - The unit. + + +The `live` block supports: + +* `delay` - The delay field. + +* `unit` - The unit. + + +The `encoder_settings_expand` block supports: + +* `audio_descriptions` - The description of the audio output configuration. + The [audio_descriptions](#LiveChannel_AudioDescriptions) structure is documented below. + + +The `audio_descriptions` block supports: + +* `name` - The name of the audio output configuration. + +* `audio_selector_name` - The audio selector name. + +* `language_code_control` - The language code control configuration. Valid values are: + + **FOLLOW_INPUT**: If the output audio corresponding to the selected audio selector has a language, it will be + consistent with it, otherwise it will be backed up by the language code and stream name configured here. + The current option is recommended and is the default value. + + **USE_CONFIGURED**: Users can customize the language and stream name of the output audio based on actual conditions. + +* `language_code` - The language code. + +* `stream_name` - The stream name. + + +The `encoder_settings` block supports: + +* `template_id` - The transcoding template ID. diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go index aed756698f4..8eec42ada85 100644 --- a/huaweicloud/provider.go +++ b/huaweicloud/provider.go @@ -921,6 +921,7 @@ func Provider() *schema.Provider { "huaweicloud_live_snapshots": live.DataSourceLiveSnapshots(), "huaweicloud_live_geo_blockings": live.DataSourceGeoBlockings(), "huaweicloud_live_record_callbacks": live.DataSourceLiveRecordCallbacks(), + "huaweicloud_live_channels": live.DataSourceLiveChannels(), "huaweicloud_lts_aom_accesses": lts.DataSourceAOMAccesses(), "huaweicloud_lts_cce_accesses": lts.DataSourceCceAccesses(), diff --git a/huaweicloud/services/acceptance/live/data_source_huaweicloud_live_channels_test.go b/huaweicloud/services/acceptance/live/data_source_huaweicloud_live_channels_test.go new file mode 100644 index 00000000000..c0e040a45e9 --- /dev/null +++ b/huaweicloud/services/acceptance/live/data_source_huaweicloud_live_channels_test.go @@ -0,0 +1,133 @@ +package live + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" +) + +func TestAccDataSourceChannels_basic(t *testing.T) { + var ( + rName = acceptance.RandomAccResourceName() + + dataSource = "data.huaweicloud_live_channels.test" + dc = acceptance.InitDataSourceCheck(dataSource) + + byDomainName = "data.huaweicloud_live_channels.filter_by_domain_name" + dcByDomainName = acceptance.InitDataSourceCheck(byDomainName) + + byAppName = "data.huaweicloud_live_channels.filter_by_app_name" + dcByAppName = acceptance.InitDataSourceCheck(byAppName) + + byChannelID = "data.huaweicloud_live_channels.filter_by_channel_id" + dcByChannelID = acceptance.InitDataSourceCheck(byChannelID) + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acceptance.TestAccPreCheck(t) + acceptance.TestAccPreCheckLiveStreamingDomainName(t) + acceptance.TestAccPreCheckLiveIngestRTMPDomainName(t) + acceptance.TestAccPreCheckLiveTranscodingTemplateID(t) + }, + ProviderFactories: acceptance.TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testDataSourceChannels_basic(rName), + Check: resource.ComposeTestCheckFunc( + dc.CheckResourceExists(), + resource.TestCheckResourceAttrSet(dataSource, "channels.0.app_name"), + resource.TestCheckResourceAttrSet(dataSource, "channels.0.domain_name"), + resource.TestCheckResourceAttrSet(dataSource, "channels.0.encoder_settings.#"), + resource.TestCheckResourceAttrSet(dataSource, "channels.0.endpoints.#"), + resource.TestCheckResourceAttrSet(dataSource, "channels.0.id"), + resource.TestCheckResourceAttrSet(dataSource, "channels.0.input.#"), + resource.TestCheckResourceAttrSet(dataSource, "channels.0.name"), + resource.TestCheckResourceAttrSet(dataSource, "channels.0.record_settings.#"), + resource.TestCheckResourceAttrSet(dataSource, "channels.0.state"), + + dcByDomainName.CheckResourceExists(), + resource.TestCheckOutput("domain_name_filter_is_useful", "true"), + + dcByAppName.CheckResourceExists(), + resource.TestCheckOutput("app_name_filter_is_useful", "true"), + + dcByChannelID.CheckResourceExists(), + resource.TestCheckOutput("channel_id_filter_is_useful", "true"), + ), + }, + }, + }) +} + +func testDataSourceChannels_basic(name string) string { + return fmt.Sprintf(` +%s + +data "huaweicloud_live_channels" "test" { + depends_on = [ + huaweicloud_live_channel.test + ] +} + +# Filter by domain_name +locals { + domain_name = data.huaweicloud_live_channels.test.channels[0].domain_name +} + +data "huaweicloud_live_channels" "filter_by_domain_name" { + domain_name = local.domain_name +} + +locals { + domain_name_filter_result = [ + for v in data.huaweicloud_live_channels.filter_by_domain_name.channels[*].domain_name : v == local.domain_name + ] +} + +output "domain_name_filter_is_useful" { + value = alltrue(local.domain_name_filter_result) && length(local.domain_name_filter_result) > 0 +} + +# Filter by app_name +locals { + app_name = data.huaweicloud_live_channels.test.channels[0].app_name +} + +data "huaweicloud_live_channels" "filter_by_app_name" { + app_name = local.app_name +} + +locals { + app_name_filter_result = [ + for v in data.huaweicloud_live_channels.filter_by_app_name.channels[*].app_name : v == local.app_name + ] +} + +output "app_name_filter_is_useful" { + value = alltrue(local.app_name_filter_result) && length(local.app_name_filter_result) > 0 +} + +# Filter by channel_id +locals { + channel_id = data.huaweicloud_live_channels.test.channels[0].id +} + +data "huaweicloud_live_channels" "filter_by_channel_id" { + channel_id = local.channel_id +} + +locals { + channel_id_filter_result = [ + for v in data.huaweicloud_live_channels.filter_by_channel_id.channels[*].id : v == local.channel_id + ] +} + +output "channel_id_filter_is_useful" { + value = alltrue(local.channel_id_filter_result) && length(local.channel_id_filter_result) > 0 +} +`, testLiveChannel_FLV_PULL(name)) +} diff --git a/huaweicloud/services/live/data_source_huaweicloud_live_channels.go b/huaweicloud/services/live/data_source_huaweicloud_live_channels.go new file mode 100644 index 00000000000..9008a23c93f --- /dev/null +++ b/huaweicloud/services/live/data_source_huaweicloud_live_channels.go @@ -0,0 +1,1365 @@ +package live + +import ( + "context" + "fmt" + "strings" + + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/chnsz/golangsdk" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils" +) + +// @API LIVE GET /v1/{project_id}/ott/channels +func DataSourceLiveChannels() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceLiveChannelsRead, + + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: `Specifies the region in which to query the resource. If omitted, the provider-level region will be used.`, + }, + "domain_name": { + Type: schema.TypeString, + Optional: true, + Description: `Specifies the channel streaming domain name.`, + }, + "app_name": { + Type: schema.TypeString, + Optional: true, + Description: `Specifies the group name or application name.`, + }, + "channel_id": { + Type: schema.TypeString, + Optional: true, + Description: `Specifies the channel ID.`, + }, + "channels": { + Type: schema.TypeList, + Computed: true, + Description: `The channel information.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "domain_name": { + Type: schema.TypeString, + Computed: true, + Description: `The channel streaming domain name.`, + }, + "app_name": { + Type: schema.TypeString, + Computed: true, + Description: `The group name or application name.`, + }, + "state": { + Type: schema.TypeString, + Computed: true, + Description: `The channel status.`, + }, + "input": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelInputSchema(), + Description: `The channel input information.`, + }, + "record_settings": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelRecordSettingsSchema(), + Description: `The configuration for replaying a recording.`, + }, + "endpoints": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelEndpointsSchema(), + Description: `The channel outflow information.`, + }, + "encoder_settings_expand": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelEncoderSettingsExpandSchema(), + Description: `The audio output configuration.`, + }, + "encoder_settings": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelEncoderSettingsSchema(), + Description: `The transcoding template configuration.`, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The channel name.`, + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: `The channel ID.`, + }, + }, + }, + }, + }, + } +} + +func dataChannelEncoderSettingsSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "template_id": { + Type: schema.TypeString, + Computed: true, + Description: `The transcoding template ID.`, + }, + }, + } + return &sc +} + +func dataChannelEncoderSettingsExpandSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "audio_descriptions": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelEncoderSettingsExpandAudioDescriptionsSchema(), + Description: `The description of the audio output configuration.`, + }, + }, + } + return &sc +} + +func dataChannelEncoderSettingsExpandAudioDescriptionsSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The name of the audio output configuration.`, + }, + "audio_selector_name": { + Type: schema.TypeString, + Computed: true, + Description: `The audio selector name.`, + }, + "language_code_control": { + Type: schema.TypeString, + Computed: true, + Description: `The language code control configuration.`, + }, + "language_code": { + Type: schema.TypeString, + Computed: true, + Description: `The language code.`, + }, + "stream_name": { + Type: schema.TypeString, + Computed: true, + Description: `The stream name.`, + }, + }, + } + return &sc +} + +func dataChannelEndpointsSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "hls_package": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelEndpointsHlsPackageSchema(), + Description: `The HLS packaging information.`, + }, + "dash_package": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelEndpointsDashPackageSchema(), + Description: `The DASH packaging information.`, + }, + "mss_package": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelEndpointsMssPackageSchema(), + Description: `The MSS packaging information.`, + }, + }, + } + return &sc +} + +func dataChannelEndpointsMssPackageSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": { + Type: schema.TypeString, + Computed: true, + Description: `The customer-defined streaming address.`, + }, + "stream_selection": { + Type: schema.TypeList, + Elem: dataChannelEndpointsStreamSelectionSchema(), + Computed: true, + Description: `The stream selection.`, + }, + "segment_duration_seconds": { + Type: schema.TypeInt, + Computed: true, + Description: `The duration of the channel output segment.`, + }, + "playlist_window_seconds": { + Type: schema.TypeInt, + Computed: true, + Description: `The window length of the channel live broadcast return shard.`, + }, + "encryption": { + Type: schema.TypeList, + Elem: dataChannelEndpointsEncryptionSchema(), + Computed: true, + Description: `The encrypted information.`, + }, + "delay_segment": { + Type: schema.TypeInt, + Computed: true, + Description: `The delayed playback time.`, + }, + "request_args": { + Type: schema.TypeList, + Elem: dataChannelEndpointsRequestArgsSchema(), + Computed: true, + Description: `The play related configuration.`, + }, + }, + } + return &sc +} + +func dataChannelEndpointsDashPackageSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": { + Type: schema.TypeString, + Computed: true, + Description: `The customer-defined streaming address.`, + }, + "stream_selection": { + Type: schema.TypeList, + Elem: dataChannelEndpointsStreamSelectionSchema(), + Computed: true, + Description: `The stream selection.`, + }, + "segment_duration_seconds": { + Type: schema.TypeInt, + Computed: true, + Description: `The duration of the channel output segment.`, + }, + "playlist_window_seconds": { + Type: schema.TypeInt, + Computed: true, + Description: `The window length of the channel live broadcast return shard.`, + }, + "encryption": { + Type: schema.TypeList, + Elem: dataChannelEndpointsEncryptionSchema(), + Computed: true, + Description: `The encrypted information.`, + }, + "request_args": { + Type: schema.TypeList, + Elem: dataChannelEndpointsRequestArgsSchema(), + Computed: true, + Description: `The play related configuration.`, + }, + "ad_marker": { + Type: schema.TypeString, + Computed: true, + Description: `The advertising marker.`, + }, + }, + } + return &sc +} + +func dataChannelEndpointsHlsPackageSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": { + Type: schema.TypeString, + Computed: true, + Description: `The customer-defined streaming address.`, + }, + "segment_duration_seconds": { + Type: schema.TypeInt, + Computed: true, + Description: `The duration of the channel output segment.`, + }, + "stream_selection": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelEndpointsStreamSelectionSchema(), + Description: `The stream selection.`, + }, + "hls_version": { + Type: schema.TypeString, + Computed: true, + Description: `The HLS version number.`, + }, + "playlist_window_seconds": { + Type: schema.TypeInt, + Computed: true, + Description: `The window length of the channel live broadcast return shard.`, + }, + "encryption": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelEndpointsEncryptionSchema(), + Description: `The encrypted information.`, + }, + "request_args": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelEndpointsRequestArgsSchema(), + Description: `The play related configuration.`, + }, + "ad_marker": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: `The advertising marker.`, + }, + }, + } + return &sc +} + +func dataChannelEndpointsRequestArgsSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "record": { + Type: schema.TypeList, + Elem: dataChannelRequestArgsRecordSchema(), + Computed: true, + Description: `The recording and playback related configuration.`, + }, + "timeshift": { + Type: schema.TypeList, + Elem: dataChannelRequestArgsTimeShiftSchema(), + Computed: true, + Description: `The time-shift playback configuration.`, + }, + "live": { + Type: schema.TypeList, + Elem: dataChannelRequestArgsLiveSchema(), + Computed: true, + Description: `The live broadcast configuration.`, + }, + }, + } + return &sc +} + +func dataChannelRequestArgsLiveSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "delay": { + Type: schema.TypeString, + Computed: true, + Description: `The delay field.`, + }, + "unit": { + Type: schema.TypeString, + Computed: true, + Description: `The unit.`, + }, + }, + } + return &sc +} + +func dataChannelRequestArgsTimeShiftSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "back_time": { + Type: schema.TypeString, + Computed: true, + Description: `The time shift duration field name.`, + }, + "unit": { + Type: schema.TypeString, + Computed: true, + Description: `The unit.`, + }, + }, + } + return &sc +} + +func dataChannelRequestArgsRecordSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "start_time": { + Type: schema.TypeString, + Computed: true, + Description: `The start time.`, + }, + "end_time": { + Type: schema.TypeString, + Computed: true, + Description: `The end time.`, + }, + "format": { + Type: schema.TypeString, + Computed: true, + Description: `The format.`, + }, + "unit": { + Type: schema.TypeString, + Computed: true, + Description: `The unit.`, + }, + }, + } + return &sc +} + +func dataChannelEndpointsEncryptionSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "resource_id": { + Type: schema.TypeString, + Computed: true, + Description: `The customer-generated DRM content ID.`, + }, + "system_ids": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: `The system ID enumeration values.`, + }, + "url": { + Type: schema.TypeString, + Computed: true, + Description: `The DRM address of the key.`, + }, + "speke_version": { + Type: schema.TypeString, + Computed: true, + Description: `The DRM spec version number.`, + }, + "request_mode": { + Type: schema.TypeString, + Computed: true, + Description: `The request mode.`, + }, + "key_rotation_interval_seconds": { + Type: schema.TypeInt, + Computed: true, + Description: `The key rotation interval seconds.`, + }, + "encryption_method": { + Type: schema.TypeString, + Computed: true, + Description: `The encryption method.`, + }, + "level": { + Type: schema.TypeString, + Computed: true, + Description: `The level.`, + }, + "http_headers": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelEncryptionHttpHeaderSchema(), + Description: `The authentication information that needs to be added to the DRM request header.`, + }, + "urn": { + Type: schema.TypeString, + Computed: true, + Description: `The URN of the function graph.`, + }, + }, + } + return &sc +} + +func dataChannelEncryptionHttpHeaderSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Computed: true, + Description: `The key field name in the request header.`, + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: `The value corresponding to the key in the request header.`, + }, + }, + } + return &sc +} + +func dataChannelEndpointsStreamSelectionSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Computed: true, + Description: `The key used for bitrate filtering in streaming URLs.`, + }, + "max_bandwidth": { + Type: schema.TypeInt, + Computed: true, + Description: `The maximum code rate.`, + }, + "min_bandwidth": { + Type: schema.TypeInt, + Computed: true, + Description: `The minimum code rate.`, + }, + }, + } + return &sc +} + +func dataChannelRecordSettingsSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "rollingbuffer_duration": { + Type: schema.TypeInt, + Computed: true, + Description: `The maximum playback recording time.`, + }, + }, + } + return &sc +} + +func dataChannelInputSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "input_protocol": { + Type: schema.TypeString, + Computed: true, + Description: `The channel input protocol.`, + }, + "sources": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelInputSourcesSchema(), + Description: `The channel main source stream information.`, + }, + "secondary_sources": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelInputSecondarySourcesSchema(), + Description: `The prepared stream array.`, + }, + "failover_conditions": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelInputFailoverConditionsSchema(), + Description: `The configuration of switching between primary and backup audio and video stream URLs.`, + }, + "max_bandwidth_limit": { + Type: schema.TypeInt, + Computed: true, + Description: `The maximum bandwidth that needs to be configured when the inbound protocol is **HLS_PULL**.`, + }, + "ip_port_mode": { + Type: schema.TypeBool, + Computed: true, + Description: `The IP port mode.`, + }, + "ip_whitelist": { + Type: schema.TypeString, + Computed: true, + Description: `The IP whitelist when protocol is **SRT_PUSH**.`, + }, + "scte35_source": { + Type: schema.TypeString, + Computed: true, + Description: `The advertisement scte35 signal source.`, + }, + "ad_triggers": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: `The ad trigger configuration.`, + }, + "audio_selectors": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelInputAudioSelectorsSchema(), + Description: `The audio selector configuration.`, + }, + }, + } + return &sc +} + +func dataChannelInputSourcesSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": { + Type: schema.TypeString, + Computed: true, + Description: `The channel source stream URL, used for external streaming.`, + }, + "bitrate": { + Type: schema.TypeInt, + Computed: true, + Description: `The bitrate.`, + }, + "width": { + Type: schema.TypeInt, + Computed: true, + Description: `The resolution corresponds to the width value.`, + }, + "height": { + Type: schema.TypeInt, + Computed: true, + Description: `The resolution corresponds to the high value.`, + }, + "enable_snapshot": { + Type: schema.TypeBool, + Computed: true, + Description: `Whether to use this stream to take screenshots.`, + }, + "bitrate_for3u8": { + Type: schema.TypeBool, + Computed: true, + Description: `Whether to use bitrate to fix the bitrate.`, + }, + "passphrase": { + Type: schema.TypeString, + Computed: true, + Description: `The encrypted information when the protocol is **SRT_PUSH**.`, + }, + "backup_urls": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: `The list of backup stream addresses.`, + }, + "stream_id": { + Type: schema.TypeString, + Computed: true, + Description: `The stream ID of the stream pull address when the channel type is **SRT_PULL**.`, + }, + "latency": { + Type: schema.TypeInt, + Computed: true, + Description: `The streaming delay when the channel type is **SRT_PULL**.`, + }, + }, + } + return &sc +} + +func dataChannelInputSecondarySourcesSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": { + Type: schema.TypeString, + Computed: true, + Description: `The channel source stream URL.`, + }, + "bitrate": { + Type: schema.TypeInt, + Computed: true, + Description: `The bitrate.`, + }, + "width": { + Type: schema.TypeInt, + Computed: true, + Description: `The resolution corresponds to the width value.`, + }, + "height": { + Type: schema.TypeInt, + Computed: true, + Description: `The resolution corresponds to the high value.`, + }, + "bitrate_for3u8": { + Type: schema.TypeBool, + Computed: true, + Description: `Whether to use bitrate to fix the bitrate.`, + }, + "passphrase": { + Type: schema.TypeString, + Computed: true, + Description: `The encrypted information when the protocol is **SRT_PUSH**.`, + }, + "backup_urls": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: `The list of backup stream addresses.`, + }, + "stream_id": { + Type: schema.TypeString, + Computed: true, + Description: `The stream ID of the stream pull address when the channel type is **SRT_PULL**.`, + }, + "latency": { + Type: schema.TypeInt, + Computed: true, + Description: `The streaming delay when the channel type is **SRT_PULL**.`, + }, + }, + } + return &sc +} + +func dataChannelInputFailoverConditionsSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "input_loss_threshold_msec": { + Type: schema.TypeInt, + Computed: true, + Description: `The duration threshold of inflow stop.`, + }, + "input_preference": { + Type: schema.TypeString, + Computed: true, + Description: `The input preference type.`, + }, + }, + } + return &sc +} + +func dataChannelInputAudioSelectorsSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The name of the audio selector.`, + }, + "selector_settings": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelAudioSelectorsSelectorSettingsSchema(), + Description: `The audio selector configuration.`, + }, + }, + } + return &sc +} + +func dataChannelAudioSelectorsSelectorSettingsSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "audio_language_selection": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelSelectorSettingsAudioLanguageSelectionSchema(), + Description: `The language selector configuration.`, + }, + "audio_pid_selection": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelSelectorSettingsAudioPidSelectionSchema(), + Description: `The PID selector configuration.`, + }, + "audio_hls_selection": { + Type: schema.TypeList, + Computed: true, + Elem: dataChannelSelectorSettingsAudioHlsSelectionSchema(), + Description: `The HLS selector configuration.`, + }, + }, + } + return &sc +} + +func dataChannelSelectorSettingsAudioLanguageSelectionSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "language_code": { + Type: schema.TypeString, + Computed: true, + Description: `The language abbreviation.`, + }, + "language_selection_policy": { + Type: schema.TypeString, + Computed: true, + Description: `The language output strategy.`, + }, + }, + } + return &sc +} + +func dataChannelSelectorSettingsAudioPidSelectionSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "pid": { + Type: schema.TypeInt, + Computed: true, + Description: `The value of PID.`, + }, + }, + } + return &sc +} + +func dataChannelSelectorSettingsAudioHlsSelectionSchema() *schema.Resource { + sc := schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The HLS audio selector name.`, + }, + "group_id": { + Type: schema.TypeString, + Computed: true, + Description: `The HLS audio selector gid.`, + }, + }, + } + return &sc +} + +func buildDatasourceChannelQueryParams(d *schema.ResourceData) string { + res := "" + if v, ok := d.GetOk("domain_name"); ok { + res = fmt.Sprintf("%s&domain=%v", res, v) + } + + if v, ok := d.GetOk("app_name"); ok { + res = fmt.Sprintf("%s&app_name=%v", res, v) + } + + if v, ok := d.GetOk("channel_id"); ok { + res = fmt.Sprintf("%s&id=%v", res, v) + } + return res +} + +func dataSourceLiveChannelsRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var ( + cfg = meta.(*config.Config) + region = cfg.GetRegion(d) + httpUrl = "v1/{project_id}/ott/channels?limit=100" + product = "live" + totalChannels []interface{} + offset = 0 + ) + client, err := cfg.NewServiceClient(product, region) + if err != nil { + return diag.Errorf("error creating Live client: %s", err) + } + + requestPath := client.Endpoint + httpUrl + requestPath = strings.ReplaceAll(requestPath, "{project_id}", client.ProjectID) + requestPath += buildDatasourceChannelQueryParams(d) + requestOpt := golangsdk.RequestOpts{ + KeepResponseBody: true, + MoreHeaders: map[string]string{"Content-Type": "application/json"}, + } + + for { + requestPathWithOffset := fmt.Sprintf("%s&offset=%d", requestPath, offset) + resp, err := client.Request("GET", requestPathWithOffset, &requestOpt) + if err != nil { + return diag.Errorf("error retrieving Live channels: %s", err) + } + + respBody, err := utils.FlattenResponse(resp) + if err != nil { + return diag.FromErr(err) + } + + channels := utils.PathSearch("channels", respBody, make([]interface{}, 0)).([]interface{}) + if len(channels) == 0 { + break + } + + totalChannels = append(totalChannels, channels...) + offset += len(channels) + } + + dataSourceId, err := uuid.GenerateUUID() + if err != nil { + return diag.Errorf("unable to generate ID: %s", err) + } + d.SetId(dataSourceId) + + mErr := multierror.Append(nil, + d.Set("region", region), + d.Set("channels", flattenDataSourceChannels(totalChannels)), + ) + return diag.FromErr(mErr.ErrorOrNil()) +} + +func flattenDataSourceChannels(totalChannels []interface{}) []interface{} { + if len(totalChannels) == 0 { + return nil + } + + result := make([]interface{}, 0, len(totalChannels)) + for _, v := range totalChannels { + result = append(result, map[string]interface{}{ + "domain_name": utils.PathSearch("domain", v, nil), + "app_name": utils.PathSearch("app_name", v, nil), + "id": utils.PathSearch("id", v, nil), + "name": utils.PathSearch("name", v, nil), + "state": utils.PathSearch("state", v, nil), + "input": flattenDataChannelInputResponseBody(v), + "encoder_settings": flattenDataChannelEncoderSettingsResponseBody(v), + "record_settings": flattenDataChannelRecordSettingsResponseBody(v), + "endpoints": flattenDataChannelEndpointsResponseBody(v), + "encoder_settings_expand": flattenDataChannelEncoderSettingsExpandResponseBody(v), + }) + } + return result +} + +func flattenDataChannelEncoderSettingsExpandResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + + respBody := utils.PathSearch("encoder_settings_expand", resp, nil) + if respBody == nil { + return nil + } + + return []interface{}{map[string]interface{}{ + "audio_descriptions": flattenDataAudioDescriptionsResponseBody(respBody), + }} +} + +func flattenDataAudioDescriptionsResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + curJson := utils.PathSearch("audio_descriptions", resp, make([]interface{}, 0)) + curArray := curJson.([]interface{}) + rst := make([]interface{}, 0, len(curArray)) + for _, v := range curArray { + rst = append(rst, map[string]interface{}{ + "name": utils.PathSearch("name", v, nil), + "audio_selector_name": utils.PathSearch("audio_selector_name", v, nil), + "language_code_control": utils.PathSearch("language_code_control", v, nil), + "language_code": utils.PathSearch("language_code", v, nil), + "stream_name": utils.PathSearch("stream_name", v, nil), + }) + } + return rst +} + +func flattenDataChannelEndpointsResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + curJson := utils.PathSearch("endpoints", resp, make([]interface{}, 0)) + curArray := curJson.([]interface{}) + rst := make([]interface{}, 0, len(curArray)) + for _, v := range curArray { + rst = append(rst, map[string]interface{}{ + "hls_package": flattenDataHlsPackageResponseBody(v), + "dash_package": flattenDataDashPackageResponseBody(v), + "mss_package": flattenDataMssPackageResponseBody(v), + }) + } + return rst +} + +func flattenDataMssPackageResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + curJson := utils.PathSearch("mss_package", resp, make([]interface{}, 0)) + curArray := curJson.([]interface{}) + rst := make([]interface{}, 0, len(curArray)) + for _, v := range curArray { + rst = append(rst, map[string]interface{}{ + "url": utils.PathSearch("url", v, nil), + "stream_selection": flattenDataStreamSelectionResponseBody(v), + "segment_duration_seconds": utils.PathSearch("segment_duration_seconds", v, nil), + "playlist_window_seconds": utils.PathSearch("playlist_window_seconds", v, nil), + "encryption": flattenDataEncryptionResponseBody(v), + "delay_segment": utils.PathSearch("delay_segment", v, nil), + "request_args": flattenDataRequestArgsResponseBody(v), + }) + } + return rst +} + +func flattenDataDashPackageResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + curJson := utils.PathSearch("dash_package", resp, make([]interface{}, 0)) + curArray := curJson.([]interface{}) + rst := make([]interface{}, 0, len(curArray)) + for _, v := range curArray { + rst = append(rst, map[string]interface{}{ + "url": utils.PathSearch("url", v, nil), + "stream_selection": flattenDataStreamSelectionResponseBody(v), + "segment_duration_seconds": utils.PathSearch("segment_duration_seconds", v, nil), + "playlist_window_seconds": utils.PathSearch("playlist_window_seconds", v, nil), + "encryption": flattenDataEncryptionResponseBody(v), + "request_args": flattenDataRequestArgsResponseBody(v), + "ad_marker": utils.PathSearch("ad_marker", v, nil), + }) + } + return rst +} + +func flattenDataHlsPackageResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + curJson := utils.PathSearch("hls_package", resp, make([]interface{}, 0)) + curArray := curJson.([]interface{}) + rst := make([]interface{}, 0, len(curArray)) + for _, v := range curArray { + rst = append(rst, map[string]interface{}{ + "url": utils.PathSearch("url", v, nil), + "stream_selection": flattenDataStreamSelectionResponseBody(v), + "hls_version": utils.PathSearch("hls_version", v, nil), + "segment_duration_seconds": utils.PathSearch("segment_duration_seconds", v, nil), + "playlist_window_seconds": utils.PathSearch("playlist_window_seconds", v, nil), + "encryption": flattenDataEncryptionResponseBody(v), + "request_args": flattenDataRequestArgsResponseBody(v), + "ad_marker": utils.PathSearch("ad_marker", v, nil), + }) + } + return rst +} + +func flattenDataRequestArgsResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + + respBody := utils.PathSearch("request_args", resp, nil) + if respBody == nil { + return nil + } + + return []interface{}{map[string]interface{}{ + "record": flattenDataRequestArgsRecordResponseBody(respBody), + "timeshift": flattenDataRequestArgsTimeShiftResponseBody(respBody), + "live": flattenDataRequestArgsLiveResponseBody(respBody), + }} +} + +func flattenDataRequestArgsLiveResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + curJson := utils.PathSearch("live", resp, make([]interface{}, 0)) + curArray := curJson.([]interface{}) + rst := make([]interface{}, 0, len(curArray)) + for _, v := range curArray { + rst = append(rst, map[string]interface{}{ + "delay": utils.PathSearch("delay", v, nil), + "unit": utils.PathSearch("unit", v, nil), + }) + } + return rst +} + +func flattenDataRequestArgsTimeShiftResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + curJson := utils.PathSearch("timeshift", resp, make([]interface{}, 0)) + curArray := curJson.([]interface{}) + rst := make([]interface{}, 0, len(curArray)) + for _, v := range curArray { + rst = append(rst, map[string]interface{}{ + "back_time": utils.PathSearch("back_time", v, nil), + "unit": utils.PathSearch("unit", v, nil), + }) + } + return rst +} + +func flattenDataRequestArgsRecordResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + curJson := utils.PathSearch("record", resp, make([]interface{}, 0)) + curArray := curJson.([]interface{}) + rst := make([]interface{}, 0, len(curArray)) + for _, v := range curArray { + rst = append(rst, map[string]interface{}{ + "start_time": utils.PathSearch("start_time", v, nil), + "end_time": utils.PathSearch("end_time", v, nil), + "format": utils.PathSearch("format", v, nil), + "unit": utils.PathSearch("unit", v, nil), + }) + } + return rst +} + +func flattenDataStreamSelectionResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + curJson := utils.PathSearch("stream_selection", resp, make([]interface{}, 0)) + curArray := curJson.([]interface{}) + rst := make([]interface{}, 0, len(curArray)) + for _, v := range curArray { + rst = append(rst, map[string]interface{}{ + "key": utils.PathSearch("key", v, nil), + "max_bandwidth": utils.PathSearch("max_bandwidth", v, nil), + "min_bandwidth": utils.PathSearch("min_bandwidth", v, nil), + }) + } + return rst +} + +func flattenDataEncryptionResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + + respBody := utils.PathSearch("encryption", resp, nil) + if respBody == nil { + return nil + } + + return []interface{}{map[string]interface{}{ + "key_rotation_interval_seconds": utils.PathSearch("key_rotation_interval_seconds", respBody, nil), + "encryption_method": utils.PathSearch("encryption_method", respBody, nil), + "level": utils.PathSearch("level", respBody, nil), + "resource_id": utils.PathSearch("resource_id", respBody, nil), + "system_ids": utils.PathSearch("system_ids", respBody, nil), + "url": utils.PathSearch("url", respBody, nil), + "speke_version": utils.PathSearch("speke_version", respBody, nil), + "request_mode": utils.PathSearch("request_mode", respBody, nil), + "http_headers": flattenDataEncryptionHttpHeadersResponseBody(respBody), + "urn": utils.PathSearch("urn", respBody, nil), + }} +} + +func flattenDataEncryptionHttpHeadersResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + curJson := utils.PathSearch("http_headers", resp, make([]interface{}, 0)) + curArray := curJson.([]interface{}) + rst := make([]interface{}, 0, len(curArray)) + for _, v := range curArray { + rst = append(rst, map[string]interface{}{ + "key": utils.PathSearch("key", v, nil), + "value": utils.PathSearch("value", v, nil), + }) + } + return rst +} + +func flattenDataChannelRecordSettingsResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + + respBody := utils.PathSearch("record_settings", resp, nil) + if respBody == nil { + return nil + } + + return []interface{}{map[string]interface{}{ + "rollingbuffer_duration": utils.PathSearch("rollingbuffer_duration", respBody, nil), + }} +} + +func flattenDataChannelEncoderSettingsResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + curJson := utils.PathSearch("encoder_settings", resp, make([]interface{}, 0)) + curArray := curJson.([]interface{}) + rst := make([]interface{}, 0, len(curArray)) + for _, v := range curArray { + rst = append(rst, map[string]interface{}{ + "template_id": utils.PathSearch("template_id", v, nil), + }) + } + return rst +} + +func flattenDataChannelInputResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + + respBody := utils.PathSearch("input", resp, nil) + if respBody == nil { + return nil + } + + return []interface{}{map[string]interface{}{ + "input_protocol": utils.PathSearch("input_protocol", respBody, nil), + "sources": flattenDataInputSourcesResponseBody(respBody), + "secondary_sources": flattenDataInputSecondarySourcesResponseBody(respBody), + "failover_conditions": flattenDataInputFailoverConditionsResponseBody(respBody), + "max_bandwidth_limit": utils.PathSearch("max_bandwidth_limit", respBody, nil), + "ip_port_mode": utils.PathSearch("ip_port_mode", respBody, nil), + "ip_whitelist": utils.PathSearch("ip_whitelist", respBody, nil), + "scte35_source": utils.PathSearch("scte35_source", respBody, nil), + "ad_triggers": utils.PathSearch("ad_triggers", respBody, nil), + "audio_selectors": flattenDataInputAudioSelectorsResponseBody(respBody), + }} +} + +func flattenDataInputSourcesResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + curJson := utils.PathSearch("sources", resp, make([]interface{}, 0)) + curArray := curJson.([]interface{}) + rst := make([]interface{}, 0, len(curArray)) + for _, v := range curArray { + rst = append(rst, map[string]interface{}{ + "url": utils.PathSearch("url", v, nil), + "bitrate": utils.PathSearch("bitrate", v, nil), + "width": utils.PathSearch("width", v, nil), + "height": utils.PathSearch("height", v, nil), + "enable_snapshot": utils.PathSearch("enable_snapshot", v, nil), + "bitrate_for3u8": utils.PathSearch("bitrate_for3u8", v, nil), + "passphrase": utils.PathSearch("passphrase", v, nil), + "backup_urls": utils.PathSearch("backup_urls", v, nil), + "stream_id": utils.PathSearch("stream_id", v, nil), + "latency": utils.PathSearch("latency", v, nil), + }) + } + return rst +} + +func flattenDataInputSecondarySourcesResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + curJson := utils.PathSearch("secondary_sources", resp, make([]interface{}, 0)) + curArray := curJson.([]interface{}) + rst := make([]interface{}, 0, len(curArray)) + for _, v := range curArray { + rst = append(rst, map[string]interface{}{ + "url": utils.PathSearch("url", v, nil), + "bitrate": utils.PathSearch("bitrate", v, nil), + "width": utils.PathSearch("width", v, nil), + "height": utils.PathSearch("height", v, nil), + "bitrate_for3u8": utils.PathSearch("bitrate_for3u8", v, nil), + "passphrase": utils.PathSearch("passphrase", v, nil), + "backup_urls": utils.PathSearch("backup_urls", v, nil), + "stream_id": utils.PathSearch("stream_id", v, nil), + "latency": utils.PathSearch("latency", v, nil), + }) + } + return rst +} + +func flattenDataInputFailoverConditionsResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + + respBody := utils.PathSearch("failover_conditions", resp, nil) + if respBody == nil { + return nil + } + + return []interface{}{map[string]interface{}{ + "input_loss_threshold_msec": utils.PathSearch("input_loss_threshold_msec", respBody, nil), + "input_preference": utils.PathSearch("input_preference", respBody, nil), + }} +} + +func flattenDataInputAudioSelectorsResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + curJson := utils.PathSearch("audio_selectors", resp, make([]interface{}, 0)) + curArray := curJson.([]interface{}) + rst := make([]interface{}, 0, len(curArray)) + for _, v := range curArray { + rst = append(rst, map[string]interface{}{ + "name": utils.PathSearch("name", v, nil), + "selector_settings": flattenDataSelectorSettingsResponseBody(v), + }) + } + return rst +} + +func flattenDataSelectorSettingsResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + + respBody := utils.PathSearch("selector_settings", resp, nil) + if respBody == nil { + return nil + } + + return []interface{}{map[string]interface{}{ + "audio_language_selection": flattenDataAudioLanguageSelectionResponseBody(respBody), + "audio_pid_selection": flattenDataAudioPidSelectionResponseBody(respBody), + "audio_hls_selection": flattenDataAudioHlsSelectionResponseBody(respBody), + }} +} + +func flattenDataAudioLanguageSelectionResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + + respBody := utils.PathSearch("audio_language_selection", resp, nil) + if respBody == nil { + return nil + } + + return []interface{}{map[string]interface{}{ + "language_code": utils.PathSearch("language_code", respBody, nil), + "language_selection_policy": utils.PathSearch("language_selection_policy", respBody, nil), + }} +} + +func flattenDataAudioPidSelectionResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + + respBody := utils.PathSearch("audio_pid_selection", resp, nil) + if respBody == nil { + return nil + } + + return []interface{}{map[string]interface{}{ + "pid": utils.PathSearch("pid", respBody, nil), + }} +} + +func flattenDataAudioHlsSelectionResponseBody(resp interface{}) []interface{} { + if resp == nil { + return nil + } + + respBody := utils.PathSearch("audio_hls_selection", resp, nil) + if respBody == nil { + return nil + } + + return []interface{}{map[string]interface{}{ + "name": utils.PathSearch("name", respBody, nil), + "group_id": utils.PathSearch("group_id", respBody, nil), + }} +}