streaming_cmcd_config_CmcdPropertyMap.js

/**
 * The copyright in this software is being made available under the BSD License,
 * included below. This software may be subject to other third party and contributor
 * rights, including patent rights, and no such rights are granted under this license.
 *
 * Copyright (c) 2024, Dash Industry Forum.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *  * Redistributions of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation and/or
 *  other materials provided with the distribution.
 *  * Neither the name of Dash Industry Forum nor the names of its
 *  contributors may be used to endorse or promote products derived from this software
 *  without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
 *  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 *  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 *  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

import Constants from '../../constants/Constants.js';

/**
 * @module CmcdPropertyMap
 * @description Declarative configuration for CMCD property mappings.
 *
 * Maps logical property names to physical paths in different sources (manifest, settings)
 * with version awareness, priority-based fallback, and optional transformations.
 *
 * This centralized configuration allows handling structure changes in CMCD settings
 * without modifying business logic across the codebase.
 *
 * @typedef {Object} PropertySource
 * @property {string} path - Dot-notation path to property (e.g., 'settings.streaming.cmcd.version')
 * @property {number} priority - Order of precedence (1 = highest)
 * @property {string} [type] - Expected data type ('string', 'number', 'boolean', 'array', 'object')
 * @property {Function} [transform] - Optional transformation function
 * @property {*} [default] - Default value if not found
 * @property {boolean} [deprecated] - Mark as deprecated for backward compatibility
 *
 * @typedef {Object} PropertyMapping
 * @property {number[]} [version] - CMCD versions this mapping applies to (omit for all versions)
 * @property {PropertySource[]} sources - Ordered list of sources to check
 */

/**
 * Property mappings for CMCD configuration
 * @type {Object.<string, PropertyMapping>}
 */
const CmcdPropertyMap = {
    /**
     * CMCD version number
     * Priority: manifest > settings > default (1)
     */
    version: {
        version: [1, 2],
        sources: [
            {
                path: 'manifestParams.version',
                priority: 1,
                type: 'number'
            },
            {
                path: 'settings.streaming.cmcd.version',
                priority: 2,
                type: 'number',
                default: Constants.CMCD_DEFAULT_VERSION
            }
        ]
    },

    /**
     * CMCD enabled flag
     * Note: This only exists in player settings, not in manifest.
     * Manifest presence (CMCDParameters tag) implies enabled=true.
     * Priority: settings > default (false)
     */
    enabled: {
        version: [1, 2],
        sources: [
            {
                path: 'settings.streaming.cmcd.enabled',
                priority: 1,
                type: 'boolean',
                default: false
            }
        ]
    },

    /**
     * Session ID (sid)
     * Priority: manifest > settings > null
     */
    sessionID: {
        version: [1, 2],
        sources: [
            {
                path: 'manifestParams.sessionID',
                priority: 1,
                type: 'string'
            },
            {
                path: 'settings.streaming.cmcd.sid',
                priority: 2,
                type: 'string',
                default: null
            }
        ]
    },

    /**
     * Content ID (cid)
     * Priority: manifest > settings > null
     */
    contentID: {
        version: [1, 2],
        sources: [
            {
                path: 'manifestParams.contentID',
                priority: 1,
                type: 'string'
            },
            {
                path: 'settings.streaming.cmcd.cid',
                priority: 2,
                type: 'string',
                default: null
            }
        ]
    },

    /**
     * Transmission mode (query, header, body)
     * Priority: manifest > settings > default (query)
     *
     * V1: Single global mode
     * V2: Can be per-target or global
     */
    mode: {
        version: [1, 2],
        sources: [
            {
                path: 'manifestParams.mode',
                priority: 1,
                type: 'string'
            },
            {
                path: 'settings.streaming.cmcd.mode',
                priority: 2,
                type: 'string',
                default: Constants.CMCD_MODE_QUERY
            }
        ]
    },

    /**
     * Requested throughput (rtp)
     * Priority: settings > null (calculated dynamically if null)
     */
    rtp: {
        version: [1, 2],
        sources: [
            {
                path: 'settings.streaming.cmcd.rtp',
                priority: 1,
                type: 'number',
                default: null
            }
        ]
    },

    /**
     * RTP safety factor for throughput calculation
     * Priority: settings > default (5)
     */
    rtpSafetyFactor: {
        version: [1, 2],
        sources: [
            {
                path: 'settings.streaming.cmcd.rtpSafetyFactor',
                priority: 1,
                type: 'number',
                default: 5
            }
        ]
    },

    /**
     * Global enabled CMCD keys
     * Priority: manifest > settings > default (all keys)
     *
     * Note: In V1, this is a global setting.
     * In V2, keys can be per-target (see targetKeys), and this serves as a fallback.
     */
    keys: {
        version: [1, 2],
        sources: [
            {
                path: 'manifestParams.keys',
                priority: 1,
                type: 'array',
                transform: (val) => {
                    // If string with spaces, split into array
                    if (typeof val === 'string') {
                        return val.split(' ');
                    }
                    return val;
                }
            },
            {
                path: 'settings.streaming.cmcd.enabledKeys',
                priority: 2,
                type: 'array',
                default: Constants.CMCD_KEYS
            }
        ]
    },

    /**
     * Request types to include CMCD data in
     * Priority: manifest > settings > default (['segment', 'mpd'])
     */
    includeInRequests: {
        version: [1, 2],
        sources: [
            {
                path: 'manifestParams.includeInRequests',
                priority: 1,
                type: 'array',
                transform: (val) => {
                    // If string with spaces, split into array
                    if (typeof val === 'string') {
                        return val.split(' ');
                    }
                    return val;
                }
            },
            {
                path: 'settings.streaming.cmcd.includeInRequests',
                priority: 2,
                type: 'array',
                default: ['segment', 'mpd']
            }
        ]
    },

    /**
     * Apply CMCD parameters from MPD manifest
     * Priority: settings > default (true)
     */
    applyParametersFromMpd: {
        version: [1, 2],
        sources: [
            {
                path: 'settings.streaming.cmcd.applyParametersFromMpd',
                priority: 1,
                type: 'boolean',
                default: true
            }
        ]
    },

    /**
     * V2: Reporting eventTargets array
     * Priority: settings > default ([])
     */
    eventTargets: {
        version: [2],
        sources: [
            {
                path: 'settings.streaming.cmcd.eventTargets',
                priority: 1,
                type: 'array',
                default: []
            }
        ]
    },

    /**
     * V2: Target enabled flag
     * Note: This is target-specific, requires context
     */
    targetEnabled: {
        version: [2],
        sources: [
            {
                path: 'settings.streaming.cmcd.eventTargets[{targetIndex}].enabled',
                priority: 1,
                type: 'boolean',
                default: true
            }
        ]
    },

    /**
     * V2: Target URL for event reporting
     * Note: This is target-specific, requires context
     */
    targetUrl: {
        version: [2],
        sources: [
            {
                path: 'settings.streaming.cmcd.eventTargets[{targetIndex}].url',
                priority: 1,
                type: 'string',
                default: null
            }
        ]
    },

    /**
     * V2: Target enabled keys (can override global keys)
     * Note: This is target-specific, requires context
     */
    targetKeys: {
        version: [2],
        sources: [
            {
                path: 'settings.streaming.cmcd.eventTargets[{targetIndex}].enabledKeys',
                priority: 1,
                type: 'array',
                default: []
            }
        ]
    },

    /**
     * V2: Target events to report
     * Note: This is target-specific, requires context
     */
    targetEvents: {
        version: [2],
        sources: [
            {
                path: 'settings.streaming.cmcd.eventTargets[{targetIndex}].events',
                priority: 1,
                type: 'array',
                default: []
            }
        ]
    },

    /**
     * V2: Target time interval for periodic reporting
     * Note: This is target-specific, requires context
     */
    targetInterval: {
        version: [2],
        sources: [
            {
                path: 'settings.streaming.cmcd.eventTargets[{targetIndex}].interval',
                priority: 1,
                type: 'number',
                default: Constants.CMCD_DEFAULT_TIME_INTERVAL
            }
        ]
    },

    /**
     * V2: Target batch size for batched reporting
     * Note: This is target-specific, requires context
     */
    targetBatchSize: {
        version: [2],
        sources: [
            {
                path: 'settings.streaming.cmcd.eventTargets[{targetIndex}].batchSize',
                priority: 1,
                type: 'number',
                default: 0
            }
        ]
    },

    /**
     * V2: Target includeInRequests filter
     * Note: This is target-specific, requires context
     */
    targetIncludeInRequests: {
        version: [2],
        sources: [
            {
                path: 'settings.streaming.cmcd.eventTargets[{targetIndex}].includeInRequests',
                priority: 1,
                type: 'array'
            },
            {
                path: 'settings.streaming.cmcd.includeInRequests',
                priority: 2,
                type: 'array',
                default: ['segment', 'mpd']
            }
        ]
    }
};

export default CmcdPropertyMap;