# Enhanced Alert

Enhanced Alert는 Stream 또는 System에서 이상 징후와 관심 패턴을 탐지하고 사용자에게 Notification을 전송하는 Module입니다. 사전 정의된 규칙으로 이상 징후와 관심 패턴을 설정할 수 있으며, 조건이 충족되면 Module이 사용자의 Notification Server로 HTTP(S) Request를 전송합니다.

## Enhanced Alert 설정하기

Enhanced Alert는 아래와 같이 `<Server>`에서 설정할 수 있습니다:

```xml
<Server version="8">
	<Alert>
		<Url>http://192.168.0.161:9595/alert/notification</Url>
		<SecretKey>1234</SecretKey>
		<Timeout>3000</Timeout>
		<RulesFile>AlertRules.xml</RulesFile>
		<Rules>
			<Ingress>
				<StreamStatus />
				<MinBitrate>2000000</MinBitrate>
				<MaxBitrate>4000000</MaxBitrate>
				<MinFramerate>15</MinFramerate>
				<MaxFramerate>60</MaxFramerate>
				<MinWidth>1280</MinWidth>
				<MinHeight>720</MinHeight>
				<MaxWidth>1920</MaxWidth>
				<MaxHeight>1080</MaxHeight>
				<MinSamplerate>16000</MinSamplerate>
				<MaxSamplerate>50400</MaxSamplerate>
				<LongKeyFrameInterval />
				<HasBFrames />
			</Ingress>
			<Egress>
				<StreamStatus />
				<LLHLSReady />
				<HLSReady />
			</Egress>
			<InternalQueueCongestion />
		</Rules>
	</Alert>
</Server>
```

<table><thead><tr><th width="139.5555419921875">Key</th><th>Description</th></tr></thead><tbody><tr><td>Url</td><td><p>Notification을 수신할 HTTP Server 주소입니다.</p><ul><li>HTTP와 HTTPS를 모두 지원합니다.</li></ul></td></tr><tr><td>SecretKey</td><td>HMAC-SHA1 암호화에 사용되는 Secret Key입니다. 자세한 내용은 아래 <a href="#security">Security</a>를 참고하십시오.</td></tr><tr><td>Timeout</td><td><p>요청 전송 후 응답을 대기하는 시간입니다.</p><ul><li>단위는 밀리초입니다.</li></ul></td></tr><tr><td>RulesFile</td><td>(Optional) Alert 탐지 규칙이 정의된 별도의 외부 파일을 참조합니다.</td></tr><tr><td>Rules</td><td><p>(Optional) 탐지할 이상 징후 및 관심 패턴을 정의합니다.</p><ul><li><code>&#x3C; RulesFile></code>이 지정된 경우, <code>&#x3C;RulesFile></code>을우선합니다.</li></ul></td></tr></tbody></table>

### Rules File 설정하기

탐지할 이상 징후와 관심 패턴을 별도의 파일로 정의할 수 있습니다. OvenMediaEngine Enterprise는 Rules File의 변경 사항을 모니터링하고, 서비스 재시작 없이 즉시 적용합니다. 운영 중에 규칙을 자주 수정해야 한다면 `<RulesFile>` 사용을 권장합니다.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<Rules>
	<Ingress>
		<StreamStatus />
		<MinBitrate>2000000</MinBitrate>
		<MaxBitrate>4000000</MaxBitrate>
		<MinFramerate>15</MinFramerate>
		<MaxFramerate>60</MaxFramerate>
		<MinWidth>1280</MinWidth>
		<MinHeight>720</MinHeight>
		<MaxWidth>1920</MaxWidth>
		<MaxHeight>1080</MaxHeight>
		<MinSamplerate>16000</MinSamplerate>
		<MaxSamplerate>50400</MaxSamplerate>
		<LongKeyFrameInterval />
		<HasBFrames />
	</Ingress>
	<Egress>
		<StreamStatus />
		<LLHLSReady />
		<HLSReady />
	</Egress>
	<InternalQueueCongestion />
</Rules>
```

#### Rules

<table><thead><tr><th width="140.111083984375">Key</th><th width="200.22216796875"></th><th>Description</th></tr></thead><tbody><tr><td>Ingress</td><td>StreamStatus</td><td>Ingress Stream의 생성, 준비 완료, 실패, 삭제 상태를 감지합니다.</td></tr><tr><td></td><td>MinBitrate</td><td>Ingress Stream의 Video Bitrate가 설정값보다 낮을 때 감지합니다.</td></tr><tr><td></td><td>MaxBitrate</td><td>Ingress Stream의 Video Bitrate가 설정값보다 높을 때 감지합니다.</td></tr><tr><td></td><td>MinFramerate</td><td>Ingress Stream의 Framerate가 설정값보다 낮을 때 감지합니다.</td></tr><tr><td></td><td>MaxFramerate</td><td>Ingress Stream의 Framerate가 설정값보다 높을 때 감지합니다.</td></tr><tr><td></td><td>MinWidth</td><td>Ingress Stream의 가로 해상도 (Width)가 설정값보다 작을 때 감지합니다.</td></tr><tr><td></td><td>MaxWidth</td><td>Ingress Stream의 가로 해상도 (Width)가 설정값보다 클 때 감지합니다.</td></tr><tr><td></td><td>MinHeight</td><td>Ingress Stream의 세로 해상도 (Height)가 설정값보다 작을 때 감지합니다.</td></tr><tr><td></td><td>MaxHeight</td><td>Ingress Stream의 세로 해상도 (Height)가 설정값보다 클 때 감지합니다.</td></tr><tr><td></td><td>MinSamplerate</td><td>Ingress Stream의 Audio Samplerate가 설정값보다 낮을 때 감지합니다.</td></tr><tr><td></td><td>MaxSamplerate</td><td>Ingress Stream의 Audio Samplerate가 설정값보다 높을 때 감지합니다.</td></tr><tr><td></td><td>LongKeyFrameInterval</td><td><p>Ingress Stream의 Keyframe Interval이 너무 길 때 감지합니다.</p><ul><li>기준은 4초 초과입니다.</li></ul></td></tr><tr><td></td><td>HasBFrames</td><td>Ingress Stream에 B-frame이 포함되어 있을 때 감지합니다.</td></tr><tr><td>Egress</td><td>StreamStatus</td><td>Egress Stream의 생성, 준비 완료, 실패, 삭제 상태를 감지합니다.</td></tr><tr><td></td><td>LLHLSReady</td><td>Low-Latency HLS 재생이 가능해지는 시점을 감지합니다.</td></tr><tr><td></td><td>HLSReady</td><td>HLS 재생이 가능해지는 시점을 감지합니다.</td></tr><tr><td></td><td>TranscodeStatus</td><td>Egress Stream의 Transcoding 과정에서 발생할 수 있는 Decoding, Encoding, Filtering의 실패 상태를 감지합니다.</td></tr><tr><td>InternalQueueCongestion</td><td></td><td>내부 Queue가 혼잡한 상황을 감지합니다.</td></tr><tr><td>Anomaly</td><td>DTSReversal</td><td>DTS가 단조 증가 하지 않는 경우를 탐지합니다.</td></tr><tr><td></td><td>DTSJump</td><td>연속된 프레임 간 DTS가 급격히 증가한 경우를 탐지합니다.</td></tr><tr><td></td><td>DTSDuplication</td><td>연속된 프레임 간 DTS가 동일한 경우를 탐지합니다.</td></tr><tr><td></td><td>PacketTimeout</td><td>지정한 시간 동안 패킷이 수신되지 않는 경우를 탐지합니다.</td></tr></tbody></table>

## Notification 구성 알아보기

### Request

```http
POST /configured/target/url HTTP/1.1
Content-Length: 1037
Content-Type: application/json
Accept: application/json
X-OME-Signature: f871jd991jj1929jsjd91pqa0amm1
{
  "sourceUri": "#default#app/stream",
  "messages": [
    {
      "code": "INGRESS_HAS_BFRAME",
      "description": "There are B-Frames in the ingress stream."
    },
    {
      "code": "INGRESS_BITRATE_LOW",
      "description": "The ingress stream's current bitrate (316228 bps) is lower than the configured bitrate (2000000 bps)"
    }
  ],
  "sourceInfo": {
    "createdTime": "2023-04-07T21:15:24.487+09:00",
    "sourceType": "Rtmp",
    "sourceUrl": "TCP://192.168.0.220:10639",
    "tracks": [
      {
        "id": 0,
        "name": "Video",
        "type": "Video",
        "video": {
          "bitrate": 300000,
          "bypass": false,
          "codec": "H264",
          "framerate": 30.0,
          "hasBframes": true,
          "height": 1080,
          "keyFrameInterval": 0,
          "width": 1920
        }
      },
      {
        "audio": {
          "bitrate": 160000,
          "bypass": false,
          "channel": 1,
          "codec": "AAC",
          "samplerate": 48000
        },
        "id": 1,
        "name": "Audio",
        "type": "Audio"
      },
      {
        "id": 2,
        "name": "Data",
        "type": "Data"
      }
    ]
  },
  "type": "INGRESS"
}
```

#### Element

다음은 JSON Payload의 각 Element에 대한 상세 설명입니다:

<table><thead><tr><th width="155.55560302734375">Element</th><th>Description</th></tr></thead><tbody><tr><td>messages</td><td><a href="#rules">Rules</a>에 의해 감지된 <a href="#messages">Messages</a> 목록입니다.</td></tr><tr><td>type</td><td>JSON Payload의 형식을 나타냅니다. 값에 따라 포함되는 Element의 정보가 달라질 수 있습니다.</td></tr><tr><td>sourceUri</td><td><p>감지된 Source의 URI 정보입니다.</p><ul><li><code>INGRESS</code>: #&#x3C;vhost>#&#x3C;application>/&#x3C;input_stream></li><li><code>EGRESS</code>: #&#x3C;vhost>#&#x3C;application>/&#x3C;output_stream></li><li><code>ANOMALY</code>: #&#x3C;vhost>#&#x3C;application>/&#x3C;input_stream></li></ul></td></tr><tr><td>sourceInfo</td><td>감지 시점의 Source 상세 정보입니다. 형식은 해당 Source를 REST API로 정보 조회한 응답과 동일합니다.</td></tr><tr><td>parentSourceUri</td><td>감지된 Source의 상위 레벨의 Source URI 정보입니다.</td></tr><tr><td>parentSourceInfo</td><td>감지  된 Source의 상황에 따라 상세 정보가 없을 수 있습니다. 이럴 때 Source를 추적 할 수 있도록 Source와 연결 된 상위 레벨의 Source에 대한 상세 정보입니다.</td></tr></tbody></table>

#### Messages

<table><thead><tr><th width="140.111083984375">Type</th><th width="299.6666259765625">Code</th><th>Description</th></tr></thead><tbody><tr><td>INGRESS</td><td>INGRESS_STREAM_CREATED</td><td>A new ingress stream has been created.</td></tr><tr><td></td><td>INGRESS_STREAM_PREPARED</td><td>A ingress stream has been prepared.</td></tr><tr><td></td><td>INGRESS_STREAM_DELETED</td><td>A ingress stream has been deleted.</td></tr><tr><td></td><td>INGRESS_STREAM_CREATION_FAILED_DUPLICATE_NAME</td><td>Failed to create stream because the specified stream name is already in use.</td></tr><tr><td></td><td>INGRESS_BITRATE_LOW</td><td>The ingress stream's current video bitrate (<code>%d</code> bps) is lower than the configured bitrate (<code>%d</code> bps).</td></tr><tr><td></td><td>INGRESS_BITRATE_HIGH</td><td>The ingress stream's current video bitrate (<code>%d</code> bps) is higher than the configured bitrate (<code>%d</code> bps).</td></tr><tr><td></td><td>INGRESS_FRAMERATE_LOW</td><td>The ingress stream's current framerate (<code>%.2f</code> fps) is lower than the configured framerate (<code>%.2f</code> fps).</td></tr><tr><td></td><td>INGRESS_FRAMERATE_HIGH</td><td>The ingress stream's current framerate (<code>%f</code> fps) is higher than the configured framerate (<code>%f</code> fps).</td></tr><tr><td></td><td>INGRESS_WIDTH_SMALL</td><td>The ingress stream's width (<code>%d</code>) is smaller than the configured width (<code>%d</code>).</td></tr><tr><td></td><td>INGRESS_WIDTH_LARGE</td><td>The ingress stream's width (<code>%d</code>) is larger than the configured width (<code>%d</code>).</td></tr><tr><td></td><td>INGRESS_HEIGHT_SMALL</td><td>The ingress stream's height (<code>%d</code>) is smaller than the configured height (<code>%d</code>).</td></tr><tr><td></td><td>INGRESS_HEIGHT_LARGE</td><td>The ingress stream's height (<code>%d</code>) is larger than the configured height (<code>%d</code>).</td></tr><tr><td></td><td>INGRESS_SAMPLERATE_LOW</td><td>The ingress stream's current audio samplerate (<code>%d</code>) is lower than the configured samplerate (<code>%d</code>).</td></tr><tr><td></td><td>INGRESS_SAMPLERATE_HIGH</td><td>The ingress stream's current audio samplerate (<code>%d</code>) is higher than the configured samplerate (<code>%d</code>).</td></tr><tr><td></td><td>INGRESS_LONG_KEY_FRAME_INTERVAL</td><td>The ingress stream's current keyframe interval (<code>%.1f</code> seconds) is too long. Please use a keyframe interval of 4 seconds or less.</td></tr><tr><td></td><td>INGRESS_HAS_BFRAME</td><td>There are B-frames in the ingress stream.</td></tr><tr><td>EGRESS</td><td>EGRESS_STREAM_CREATED</td><td>A new egress stream has been created.</td></tr><tr><td></td><td>EGRESS_STREAM_PREPARED</td><td>A egress stream has been prepared.</td></tr><tr><td></td><td>EGRESS_STREAM_DELETED</td><td>A egress stream has been deleted.</td></tr><tr><td></td><td>EGRESS_STREAM_CREATION_FAILED_OUTPUT_PROFILE</td><td>Failed to create egress stream because the output profile configuration is invalid</td></tr><tr><td></td><td>EGRESS_STREAM_CREATION_FAILED_DECODER</td><td>Failed to create egress stream because the decoder could not be created</td></tr><tr><td></td><td>EGRESS_STREAM_CREATION_FAILED_ENCODER</td><td>Failed to create egress stream because the encoder could not be created</td></tr><tr><td></td><td>EGRESS_STREAM_CREATION_FAILED_FILTER</td><td>Failed to create egress stream because the filter could not be created</td></tr><tr><td></td><td>EGRESS_LLHLS_READY</td><td>Low-Latency HLS stream is ready to play - initial segment(s) have been generated.</td></tr><tr><td></td><td>EGRESS_HLS_READY</td><td>HLS stream is ready to play - initial segment(s) have been generated.</td></tr><tr><td></td><td>EGRESS_TRANSCODE_FAILED_DECODING</td><td>Failed to transcode the egress stream due to a frame decoding failure.</td></tr><tr><td></td><td>EGRESS_TRANSCODE_FAILED_ENCODING</td><td>Failed to transcode the egress stream due to a frame encoding failure.</td></tr><tr><td></td><td>EGRESS_TRANSCODE_FAILED_FILTERING</td><td>Failed to transcode the egress stream due to a frame filtering failure.</td></tr><tr><td>INTERNAL_QUEUE</td><td>INTERNAL_QUEUE</td><td>Internal queue(s) is currently congested</td></tr><tr><td>ANOMALY</td><td>ANOMALY_DTS_REVERSAL_DETECTED</td><td>DTS has been reversed by <code>%lld</code>.</td></tr><tr><td></td><td>ANOMALY_DTS_JUMP_DETECTED</td><td>DTS has increased significantly by <code>%lld</code>.</td></tr><tr><td></td><td>ANOMALY_DTS_DUPLICATION_DETECTED</td><td>DTS has been duplicated <code>%d</code> times.</td></tr><tr><td></td><td>ANOMALY_PACKET_TIMEOUT_DETECTED</td><td>No packets have been received for <code>%lld</code>ms.</td></tr></tbody></table>

#### Additional Element (`EGRESS_STREAM_CREATION_FAILED`)

다음은 Egress Stream 생성 실패 시 제공되는 추가 정보입니다.

**Egress Stream 실패 예제:**

<details>

<summary><mark style="color:green;">#01</mark> Output Track 생성 실패:</summary>

```json
{
  "type": "EGRESS",
  "parentSourceUri": "#default#app/stream1",
  "parentSourceInfo": {
    "createdTime": "2025-12-13T02:19:59.256+09:00",
    "name": "stream1",
    "sourceType": "Scheduled",
    "tracks": [
      {
        "id": 0,
        "name": "Video",
        "type": "Video",
        "video": {
          "bitrate": 3898586,
          "bitrateAvg": 0,
          "bitrateConf": 3898586,
          "bitrateLatest": 0,
          "bypass": false,
          "codec": "H264",
          "deltaFramesSinceLastKeyFrame": 1,
          "framerate": 60.0,
          "framerateAvg": 0.0,
          "framerateConf": 60.0,
          "framerateLatest": 0.0,
          "hasBframes": false,
          "height": 1080,
          "keyFrameInterval": 1.0,
          "keyFrameIntervalAvg": 1.0,
          "keyFrameIntervalConf": 0.0,
          "keyFrameIntervalLatest": 0.0,
          "width": 1920
        }
      },
      {
        "audio": {
          "bitrate": 127999,
          "bitrateAvg": 0,
          "bitrateConf": 127999,
          "bitrateLatest": 0,
          "bypass": false,
          "channel": 2,
          "codec": "AAC",
          "samplerate": 44100
        },
        "id": 100,
        "name": "Audio",
        "type": "Audio"
      },
      {
        "id": 200,
        "name": "Data",
        "type": "Data"
      }
    ]
  },
  "messages": [
    {
      "code": "EGRESS_STREAM_CREATION_FAILED_BY_OUTPUT_PROFILE",
      "description": "Failed to create egress stream because the output profile configuration is invalid"
    }
  ],
  "extraInfo": {
    "outputProfile": {
      "encodes": {
        "audios": [
          {
            "bypass": "true",
            "name": "bypass_audio"
          },
          {
            "bitrate": "128000",
            "bypassIfMatch": {
              "codec": "eq"
            },
            "channel": "2",
            "codec": "opus",
            "name": "opus_audio",
            "samplerate": "48000"
          }
        ],
        "videos": [
          {
            "bypass": "true",
            "name": "bypass_video"
          },
          {
            "bFrames": "2",
            "bitrate": "7000000",
            "codec": "h264",
            "framerate": "60",
            "height": "1080",
            "keyFrameInterval": "120",
            "name": "video_1080",
            "preset": "faster",
            "profile": "high",
            "width": "1920"
          }
        ]
      },
      "name": "high",
      "outputStreamName": "${OriginStreamName}"
    }
  }
}
```

</details>

<details>

<summary><mark style="color:purple;">#02-1</mark> Decoder 생성 실패:</summary>

```json
{
  "type": "EGRESS",
  "parentSourceUri": "#default#app/stream1",
  "parentSourceInfo": {
    "createdTime": "2025-12-13T02:14:34.972+09:00",
    "name": "stream1",
    "sourceType": "Scheduled",
    "tracks": [
      {
        "id": 0,
        "name": "Video",
        "type": "Video",
        "video": {
          "bitrate": 3898586,
          "bitrateAvg": 0,
          "bitrateConf": 3898586,
          "bitrateLatest": 0,
          "bypass": false,
          "codec": "H264",
          "deltaFramesSinceLastKeyFrame": 1,
          "framerate": 60.0,
          "framerateAvg": 0.0,
          "framerateConf": 60.0,
          "framerateLatest": 0.0,
          "hasBframes": false,
          "height": 1080,
          "keyFrameInterval": 1.0,
          "keyFrameIntervalAvg": 1.0,
          "keyFrameIntervalConf": 0.0,
          "keyFrameIntervalLatest": 0.0,
          "width": 1920
        }
      },
      {
        "audio": {
          "bitrate": 127999,
          "bitrateAvg": 0,
          "bitrateConf": 127999,
          "bitrateLatest": 0,
          "bypass": false,
          "channel": 2,
          "codec": "AAC",
          "samplerate": 44100
        },
        "id": 100,
        "name": "Audio",
        "type": "Audio"
      },
      {
        "id": 200,
        "name": "Data",
        "type": "Data"
      }
    ]
  },
  "messages": [
    {
      "code": "EGRESS_STREAM_CREATION_FAILED_BY_DECODER",
      "description": "Failed to create egress stream because the decoder could not be created"
    }
  ],
  "extraInfo": {
    "codecModule": {
      "busId": "-",
      "displayName": "FFmpeg Video Codecs",
      "id": 0,
      "isDecoder": true,
      "isDefault": true,
      "isEncoder": false,
      "isHwAccel": false,
      "mediaType": "Video",
      "metrics": {
        "active": {
          "decoder": 0,
          "encoder": 0
        }
      },
      "module": "default",
      "name": "default:0",
      "supportedCodecs": [
        "H264",
        "H265",
        "VP8"
      ]
    },
    "parentSourceTrackId": 0
  }
}
```

</details>

<details>

<summary><mark style="color:purple;">#02-2</mark> Encoder 생성 실패:</summary>

```json
{
  "extraInfo": {
    "codecModule": {
      "busId": "00000000:3B:00.0",
      "displayName": "NVIDIA GeForce GTX 1050",
      "id": 0,
      "isDecoder": true,
      "isDefault": false,
      "isEncoder": true,
      "isHwAccel": true,
      "mediaType": "Video",
      "metrics": {
        "active": {
          "decoder": 0,
          "encoder": 0
        }
      },
      "module": "nv",
      "name": "nv:0",
      "supportedCodecs": [
        "H264",
        "H265"
      ]
    },
    "outputProfile": {
      "encodes": {
        "audios": [
          {
            "bypass": "true",
            "name": "bypass_audio"
          },
          {
            "bitrate": "128000",
            "bypassIfMatch": {
              "codec": "eq"
            },
            "channel": "2",
            "codec": "opus",
            "name": "opus_audio",
            "samplerate": "48000"
          }
        ],
        "videos": [
          {
            "bypass": "true",
            "name": "bypass_video"
          },
          {
            "bFrames": "2",
            "bitrate": "7000000",
            "codec": "h264",
            "framerate": "60",
            "height": "1080",
            "keyFrameInterval": "120",
            "name": "video_1080",
            "preset": "faster",
            "profile": "high",
            "width": "1920"
          }
        ]
      },
      "name": "high",
      "outputStreamName": "${OriginStreamName}"
    },
    "parentSourceTrackId": 0,
    "sourceTrackId": 1
  },
  "messages": [
    {
      "code": "EGRESS_STREAM_CREATION_FAILED_ENCODER",
      "description": "Failed to create stream because the encoder could not be created"
    }
  ],
  "parentSourceInfo": {
    "createdTime": "2025-12-15T11:55:50.029+09:00",
    "name": "stream1",
    "sourceType": "Rtmp",
    "sourceUrl": "TCP://192.168.0.245:3805",
    "tracks": [
      {
        "id": 0,
        "name": "Video",
        "type": "Video",
        "video": {
          "bitrate": 30000000,
          "bitrateAvg": 0,
          "bitrateConf": 30000000,
          "bitrateLatest": 0,
          "bypass": false,
          "codec": "H264",
          "deltaFramesSinceLastKeyFrame": 24,
          "framerate": 60.0,
          "framerateAvg": 0.0,
          "framerateConf": 60.0,
          "framerateLatest": 0.0,
          "hasBframes": true,
          "height": 1080,
          "keyFrameInterval": 1.0,
          "keyFrameIntervalAvg": 1.0,
          "keyFrameIntervalConf": 0.0,
          "keyFrameIntervalLatest": 0.0,
          "width": 1920
        }
      },
      {
        "audio": {
          "bitrate": 160000,
          "bitrateAvg": 0,
          "bitrateConf": 160000,
          "bitrateLatest": 0,
          "bypass": false,
          "channel": 2,
          "codec": "AAC",
          "samplerate": 44100
        },
        "id": 1,
        "name": "Audio",
        "type": "Audio"
      },
      {
        "id": 2,
        "name": "Data",
        "type": "Data"
      }
    ]
  },
  "parentSourceUri": "#default#app/stream1",
  "sourceInfo": {
    "createdTime": "2025-12-15T11:55:50.048+09:00",
    "name": "stream1",
    "sourceType": "Transcoder",
    "sourceUrl": "da4da9dc-4e0f-41de-b623-4a8f3ed8a4c5/#default#app/stream1/i",
    "tracks": [
      {
        "id": 0,
        "name": "bypass_video",
        "type": "Video",
        "video": {
          "bitrate": 30000000,
          "bitrateAvg": 0,
          "bitrateConf": 30000000,
          "bitrateLatest": -1980852460,
          "bypass": true,
          "codec": "H264",
          "deltaFramesSinceLastKeyFrame": 23,
          "framerate": 60.0,
          "framerateAvg": 0.0,
          "framerateConf": 60.0,
          "framerateLatest": 0.0,
          "hasBframes": true,
          "height": 1080,
          "keyFrameInterval": 1.0,
          "keyFrameIntervalAvg": 1.0,
          "keyFrameIntervalConf": 0.0,
          "keyFrameIntervalLatest": 0.0,
          "width": 1920
        }
      },
      {
        "id": 1,
        "name": "video_1080",
        "type": "Video",
        "video": {
          "bitrate": 7000000,
          "bitrateAvg": 0,
          "bitrateConf": 7000000,
          "bitrateLatest": 123084383,
          "bypass": false,
          "codec": "H264",
          "deltaFramesSinceLastKeyFrame": 0,
          "framerate": 60.0,
          "framerateAvg": 0.0,
          "framerateConf": 60.0,
          "framerateLatest": 0.0,
          "hasBframes": false,
          "height": 1080,
          "keyFrameInterval": 120.0,
          "keyFrameIntervalAvg": 0.0,
          "keyFrameIntervalConf": 120.0,
          "keyFrameIntervalLatest": 0.0,
          "width": 1920
        }
      },
      {
        "audio": {
          "bitrate": 160000,
          "bitrateAvg": 0,
          "bitrateConf": 160000,
          "bitrateLatest": -374024710,
          "bypass": true,
          "channel": 2,
          "codec": "AAC",
          "samplerate": 44100
        },
        "id": 2,
        "name": "bypass_audio",
        "type": "Audio"
      },
      {
        "audio": {
          "bitrate": 128000,
          "bitrateAvg": 0,
          "bitrateConf": 128000,
          "bitrateLatest": -1130268890,
          "bypass": false,
          "channel": 2,
          "codec": "OPUS",
          "samplerate": 48000
        },
        "id": 3,
        "name": "opus_audio",
        "type": "Audio"
      },
      {
        "id": 4,
        "name": "Data",
        "type": "Data"
      }
    ]
  },
  "sourceUri": "#default#app/stream1",
  "type": "EGRESS"
}
```

</details>

<details>

<summary><mark style="color:purple;">#02-3</mark> Filter 생성 실패:</summary>

```json
{
  "extraInfo": {
    "codecModule": {
      "busId": "00000000:3B:00.0",
      "displayName": "NVIDIA GeForce GTX 1050",
      "id": 0,
      "isDecoder": true,
      "isDefault": false,
      "isEncoder": true,
      "isHwAccel": true,
      "mediaType": "Video",
      "metrics": {
        "active": {
          "decoder": 0,
          "encoder": 1
        }
      },
      "module": "nv",
      "name": "nv:0",
      "supportedCodecs": [
        "H264",
        "H265"
      ]
    },
    "outputProfile": {
      "encodes": {
        "audios": [
          {
            "bypass": "true",
            "name": "bypass_audio"
          },
          {
            "bitrate": "128000",
            "bypassIfMatch": {
              "codec": "eq"
            },
            "channel": "2",
            "codec": "opus",
            "name": "opus_audio",
            "samplerate": "48000"
          }
        ],
        "videos": [
          {
            "bypass": "true",
            "name": "bypass_video"
          },
          {
            "bFrames": "2",
            "bitrate": "7000000",
            "codec": "h264",
            "framerate": "60",
            "height": "1080",
            "keyFrameInterval": "120",
            "name": "video_1080",
            "preset": "faster",
            "profile": "high",
            "width": "1920"
          }
        ]
      },
      "name": "high",
      "outputStreamName": "${OriginStreamName}"
    },
    "parentSourceTrackId": 0,
    "sourceTrackId": 1
  },
  "messages": [
    {
      "code": "EGRESS_STREAM_CREATION_FAILED_FILTER",
      "description": "Failed to create stream because the filter could not be created"
    }
  ],
  "parentSourceInfo": {
    "createdTime": "2025-12-15T11:57:32.668+09:00",
    "name": "stream1",
    "sourceType": "Rtmp",
    "sourceUrl": "TCP://192.168.0.245:3830",
    "tracks": [
      {
        "id": 0,
        "name": "Video",
        "type": "Video",
        "video": {
          "bitrate": 30000000,
          "bitrateAvg": 0,
          "bitrateConf": 30000000,
          "bitrateLatest": 1835102790,
          "bypass": false,
          "codec": "H264",
          "deltaFramesSinceLastKeyFrame": 13,
          "framerate": 60.0,
          "framerateAvg": 0.0,
          "framerateConf": 60.0,
          "framerateLatest": 0.0,
          "hasBframes": true,
          "height": 1080,
          "keyFrameInterval": 1.0,
          "keyFrameIntervalAvg": 1.0,
          "keyFrameIntervalConf": 0.0,
          "keyFrameIntervalLatest": 0.0,
          "width": 1920
        }
      },
      {
        "audio": {
          "bitrate": 160000,
          "bitrateAvg": 0,
          "bitrateConf": 160000,
          "bitrateLatest": 695105391,
          "bypass": false,
          "channel": 2,
          "codec": "AAC",
          "samplerate": 44100
        },
        "id": 1,
        "name": "Audio",
        "type": "Audio"
      },
      {
        "id": 2,
        "name": "Data",
        "type": "Data"
      }
    ]
  },
  "parentSourceUri": "#default#app/stream1",
  "sourceInfo": {
    "createdTime": "2025-12-15T11:57:32.683+09:00",
    "name": "stream1",
    "sourceType": "Transcoder",
    "sourceUrl": "da4da9dc-4e0f-41de-b623-4a8f3ed8a4c5/#default#app/stream1/i",
    "tracks": [
      {
        "id": 0,
        "name": "bypass_video",
        "type": "Video",
        "video": {
          "bitrate": 30000000,
          "bitrateAvg": 0,
          "bitrateConf": 30000000,
          "bitrateLatest": 842608930,
          "bypass": true,
          "codec": "H264",
          "deltaFramesSinceLastKeyFrame": 12,
          "framerate": 60.0,
          "framerateAvg": 0.0,
          "framerateConf": 60.0,
          "framerateLatest": 0.0,
          "hasBframes": true,
          "height": 1080,
          "keyFrameInterval": 1.0,
          "keyFrameIntervalAvg": 1.0,
          "keyFrameIntervalConf": 0.0,
          "keyFrameIntervalLatest": 0.0,
          "width": 1920
        }
      },
      {
        "id": 1,
        "name": "video_1080",
        "type": "Video",
        "video": {
          "bitrate": 7000000,
          "bitrateAvg": 0,
          "bitrateConf": 7000000,
          "bitrateLatest": 0,
          "bypass": false,
          "codec": "H264",
          "deltaFramesSinceLastKeyFrame": 0,
          "framerate": 60.0,
          "framerateAvg": 0.0,
          "framerateConf": 60.0,
          "framerateLatest": 0.0,
          "hasBframes": false,
          "height": 1080,
          "keyFrameInterval": 120.0,
          "keyFrameIntervalAvg": 0.0,
          "keyFrameIntervalConf": 120.0,
          "keyFrameIntervalLatest": 0.0,
          "width": 1920
        }
      },
      {
        "audio": {
          "bitrate": 160000,
          "bitrateAvg": 0,
          "bitrateConf": 160000,
          "bitrateLatest": 0,
          "bypass": true,
          "channel": 2,
          "codec": "AAC",
          "samplerate": 44100
        },
        "id": 2,
        "name": "bypass_audio",
        "type": "Audio"
      },
      {
        "audio": {
          "bitrate": 128000,
          "bitrateAvg": 0,
          "bitrateConf": 128000,
          "bitrateLatest": 0,
          "bypass": false,
          "channel": 2,
          "codec": "OPUS",
          "samplerate": 48000
        },
        "id": 3,
        "name": "opus_audio",
        "type": "Audio"
      },
      {
        "id": 4,
        "name": "Data",
        "type": "Data"
      }
    ]
  },
  "sourceUri": "#default#app/stream1",
  "type": "EGRESS"
}
```

</details>

<details>

<summary><mark style="color:orange;">#03-1</mark> Frame Decoding 실패:</summary>

```json
{
  "type": "EGRESS",
  "parentSourceUri": "#default#app/stream1",
  "parentSourceInfo": {
    "createdTime": "2025-12-12T18:31:41.139+09:00",
    "name": "stream1",
    "sourceType": "Scheduled",
    "tracks": [
      {
        "id": 0,
        "name": "Video",
        "type": "Video",
        "video": {
          "bitrate": 3898586,
          "bitrateAvg": 2299712,
          "bitrateConf": 3898586,
          "bitrateLatest": 2275110,
          "bypass": false,
          "codec": "H264",
          "deltaFramesSinceLastKeyFrame": 173,
          "framerate": 60.0,
          "framerateAvg": 60.0,
          "framerateConf": 60.0,
          "framerateLatest": 60.039371490478516,
          "hasBframes": true,
          "height": 1080,
          "keyFrameInterval": 1.0,
          "keyFrameIntervalAvg": 1.0,
          "keyFrameIntervalConf": 0.0,
          "keyFrameIntervalLatest": 0.0,
          "width": 1920
        }
      },
      {
        "audio": {
          "bitrate": 127999,
          "bitrateAvg": 130655,
          "bitrateConf": 127999,
          "bitrateLatest": 131385,
          "bypass": false,
          "channel": 2,
          "codec": "AAC",
          "samplerate": 44100
        },
        "id": 100,
        "name": "Audio",
        "type": "Audio"
      },
      {
        "id": 200,
        "name": "Data",
        "type": "Data"
      }
    ]
  },
  "messages": [
    {
      "code": "EGRESS_TRANSCODE_FAILED_DECODING",
      "description": "Failed to decode frames"
    }
  ],
  "extraInfo": {
    "codecModule": {
      "busId": "-",
      "displayName": "FFmpeg Audio Codecs",
      "id": 0,
      "isDecoder": true,
      "isDefault": true,
      "isEncoder": false,
      "isHwAccel": false,
      "mediaType": "Audio",
      "metrics": {
        "active": {
          "decoder": 1,
          "encoder": 0
        }
      },
      "module": "default",
      "name": "default:0",
      "supportedCodecs": [
        "AAC",
        "OPUS"
      ]
    },
    "errorCount": 50,
    "errorEvaluationInterval": 5000,
    "parentSourceTrackId": 100
  }
}
```

</details>

<details>

<summary><mark style="color:orange;">#03-2</mark> Frame Encoding 실패:</summary>

```json
{
  "type": "EGRESS",
  "sourceUri": "#default#app/stream1",
  "sourceInfo": {
    "createdTime": "2025-12-12T18:31:41.155+09:00",
    "name": "stream1",
    "sourceType": "Transcoder",
    "sourceUrl": "da4da9dc-4e0f-41de-b623-4a8f3ed8a4c5/#default#app/stream1/i",
    "tracks": [
      {
        "id": 0,
        "name": "bypass_video",
        "type": "Video",
        "video": {
          "bitrate": 3898586,
          "bitrateAvg": 3249288,
          "bitrateConf": 3898586,
          "bitrateLatest": 2977072,
          "bypass": true,
          "codec": "H264",
          "deltaFramesSinceLastKeyFrame": 265,
          "framerate": 60.0,
          "framerateAvg": 60.0,
          "framerateConf": 60.0,
          "framerateLatest": 60.0,
          "hasBframes": true,
          "height": 1080,
          "keyFrameInterval": 1.0,
          "keyFrameIntervalAvg": 1.0,
          "keyFrameIntervalConf": 0.0,
          "keyFrameIntervalLatest": 0.0,
          "width": 1920
        }
      },
      {
        "id": 1,
        "name": "video_1080",
        "type": "Video",
        "video": {
          "bitrate": 7000000,
          "bitrateAvg": 1591632,
          "bitrateConf": 7000000,
          "bitrateLatest": 1582415,
          "bypass": false,
          "codec": "H264",
          "deltaFramesSinceLastKeyFrame": 9,
          "framerate": 60.0,
          "framerateAvg": 60.0,
          "framerateConf": 60.0,
          "framerateLatest": 62.376235961914062,
          "hasBframes": false,
          "height": 1080,
          "keyFrameInterval": 120.0,
          "keyFrameIntervalAvg": 80.333335876464844,
          "keyFrameIntervalConf": 120.0,
          "keyFrameIntervalLatest": 120.0,
          "width": 1920
        }
      },
      {
        "audio": {
          "bitrate": 127999,
          "bitrateAvg": 130459,
          "bitrateConf": 127999,
          "bitrateLatest": 130048,
          "bypass": true,
          "channel": 2,
          "codec": "AAC",
          "samplerate": 44100
        },
        "id": 2,
        "name": "bypass_audio",
        "type": "Audio"
      },
      {
        "audio": {
          "bitrate": 128000,
          "bitrateAvg": 128000,
          "bitrateConf": 128000,
          "bitrateLatest": 245681,
          "bypass": false,
          "channel": 2,
          "codec": "OPUS",
          "samplerate": 48000
        },
        "id": 3,
        "name": "opus_audio",
        "type": "Audio"
      },
      {
        "id": 4,
        "name": "Data",
        "type": "Data"
      }
    ]
  },
  "parentSourceUri": "#default#app/stream1",
  "parentSourceInfo": {
    "createdTime": "2025-12-12T18:31:41.139+09:00",
    "name": "stream1",
    "sourceType": "Scheduled",
    "tracks": [
      {
        "id": 0,
        "name": "Video",
        "type": "Video",
        "video": {
          "bitrate": 3898586,
          "bitrateAvg": 3249288,
          "bitrateConf": 3898586,
          "bitrateLatest": 2983512,
          "bypass": false,
          "codec": "H264",
          "deltaFramesSinceLastKeyFrame": 266,
          "framerate": 60.0,
          "framerateAvg": 60.0,
          "framerateConf": 60.0,
          "framerateLatest": 60.0,
          "hasBframes": true,
          "height": 1080,
          "keyFrameInterval": 1.0,
          "keyFrameIntervalAvg": 1.0,
          "keyFrameIntervalConf": 0.0,
          "keyFrameIntervalLatest": 0.0,
          "width": 1920
        }
      },
      {
        "audio": {
          "bitrate": 127999,
          "bitrateAvg": 130459,
          "bitrateConf": 127999,
          "bitrateLatest": 128983,
          "bypass": false,
          "channel": 2,
          "codec": "AAC",
          "samplerate": 44100
        },
        "id": 100,
        "name": "Audio",
        "type": "Audio"
      },
      {
        "id": 200,
        "name": "Data",
        "type": "Data"
      }
    ]
  },
  "messages": [
    {
      "code": "EGRESS_TRANSCODE_FAILED_ENCODING",
      "description": "Failed to encode frames"
    }
  ],
  "extraInfo": {
    "codecModule": {
      "busId": "-",
      "displayName": "Opus Interactive Audio Codec",
      "id": 0,
      "isDecoder": false,
      "isDefault": true,
      "isEncoder": true,
      "isHwAccel": false,
      "mediaType": "Audio",
      "metrics": {
        "active": {
          "decoder": 0,
          "encoder": 1
        }
      },
      "module": "libopus",
      "name": "libopus:0",
      "supportedCodecs": [
        "OPUS"
      ]
    },
    "errorCount": 100,
    "errorEvaluationInterval": 5000,
    "parentSourceTrackId": 100,
    "sourceTrackId": 3
  }
}
```

</details>

<details>

<summary><mark style="color:orange;">#03-3</mark> Frame Filtering 실패:</summary>

```json
{
  "type": "EGRESS",
  "sourceUri": "#default#app/stream1",
  "sourceInfo": {
    "createdTime": "2025-12-12T18:31:41.155+09:00",
    "name": "stream1",
    "sourceType": "Transcoder",
    "sourceUrl": "da4da9dc-4e0f-41de-b623-4a8f3ed8a4c5/#default#app/stream1/i",
    "tracks": [
      {
        "id": 0,
        "name": "bypass_video",
        "type": "Video",
        "video": {
          "bitrate": 3898586,
          "bitrateAvg": 2299712,
          "bitrateConf": 3898586,
          "bitrateLatest": 2296848,
          "bypass": true,
          "codec": "H264",
          "deltaFramesSinceLastKeyFrame": 157,
          "framerate": 60.0,
          "framerateAvg": 60.0,
          "framerateConf": 60.0,
          "framerateLatest": 60.0,
          "hasBframes": true,
          "height": 1080,
          "keyFrameInterval": 1.0,
          "keyFrameIntervalAvg": 1.0,
          "keyFrameIntervalConf": 0.0,
          "keyFrameIntervalLatest": 0.0,
          "width": 1920
        }
      },
      {
        "id": 1,
        "name": "video_1080",
        "type": "Video",
        "video": {
          "bitrate": 7000000,
          "bitrateAvg": 905512,
          "bitrateConf": 7000000,
          "bitrateLatest": 895276,
          "bypass": false,
          "codec": "H264",
          "deltaFramesSinceLastKeyFrame": 26,
          "framerate": 60.0,
          "framerateAvg": 60.0,
          "framerateConf": 60.0,
          "framerateLatest": 59.642147064208984,
          "hasBframes": false,
          "height": 1080,
          "keyFrameInterval": 120.0,
          "keyFrameIntervalAvg": 60.5,
          "keyFrameIntervalConf": 120.0,
          "keyFrameIntervalLatest": 120.0,
          "width": 1920
        }
      },
      {
        "audio": {
          "bitrate": 127999,
          "bitrateAvg": 130655,
          "bitrateConf": 127999,
          "bitrateLatest": 130696,
          "bypass": true,
          "channel": 2,
          "codec": "AAC",
          "samplerate": 44100
        },
        "id": 2,
        "name": "bypass_audio",
        "type": "Audio"
      },
      {
        "audio": {
          "bitrate": 128000,
          "bitrateAvg": 128000,
          "bitrateConf": 128000,
          "bitrateLatest": 125417,
          "bypass": false,
          "channel": 2,
          "codec": "OPUS",
          "samplerate": 48000
        },
        "id": 3,
        "name": "opus_audio",
        "type": "Audio"
      },
      {
        "id": 4,
        "name": "Data",
        "type": "Data"
      }
    ]
  },
  "parentSourceUri": "#default#app/stream1",
  "parentSourceInfo": {
    "createdTime": "2025-12-12T18:31:41.139+09:00",
    "name": "stream1",
    "sourceType": "Scheduled",
    "tracks": [
      {
        "id": 0,
        "name": "Video",
        "type": "Video",
        "video": {
          "bitrate": 3898586,
          "bitrateAvg": 2299712,
          "bitrateConf": 3898586,
          "bitrateLatest": 2275110,
          "bypass": false,
          "codec": "H264",
          "deltaFramesSinceLastKeyFrame": 158,
          "framerate": 60.0,
          "framerateAvg": 60.0,
          "framerateConf": 60.0,
          "framerateLatest": 60.039371490478516,
          "hasBframes": true,
          "height": 1080,
          "keyFrameInterval": 1.0,
          "keyFrameIntervalAvg": 1.0,
          "keyFrameIntervalConf": 0.0,
          "keyFrameIntervalLatest": 0.0,
          "width": 1920
        }
      },
      {
        "audio": {
          "bitrate": 127999,
          "bitrateAvg": 130655,
          "bitrateConf": 127999,
          "bitrateLatest": 131385,
          "bypass": false,
          "channel": 2,
          "codec": "AAC",
          "samplerate": 44100
        },
        "id": 100,
        "name": "Audio",
        "type": "Audio"
      },
      {
        "id": 200,
        "name": "Data",
        "type": "Data"
      }
    ]
  },
  "messages": [
    {
      "code": "EGRESS_TRANSCODE_FAILED_FILTERING",
      "description": "Failed to filter frames"
    }
  ],
  "extraInfo": {
    "codecModule": {
      "busId": "-",
      "displayName": "Opus Interactive Audio Codec",
      "id": 0,
      "isDecoder": false,
      "isDefault": true,
      "isEncoder": true,
      "isHwAccel": false,
      "mediaType": "Audio",
      "metrics": {
        "active": {
          "decoder": 0,
          "encoder": 1
        }
      },
      "module": "libopus",
      "name": "libopus:0",
      "supportedCodecs": [
        "OPUS"
      ]
    },
    "errorCount": 49,
    "errorEvaluationInterval": 5000,
    "parentSourceTrackId": 100,
    "sourceTrackId": 3
  }
}
```

</details>

**`type`이 `EGRESS`인 경우 전달되는 데이터:**

<table><thead><tr><th width="280.00018310546875">Element</th><th>Description</th></tr></thead><tbody><tr><td><code>sourceInfo</code></td><td>Egress Stream 정보입니다.</td></tr><tr><td><code>parentSourceInfo</code></td><td>Ingress Stream 정보입니다.</td></tr><tr><td><code>extraInfo.outputProfil</code></td><td>Stream 생성 실패 또는 Transcoding 실패와 관련된 Output Profile 정보입니다.</td></tr><tr><td><code>extraInto.codecModule</code></td><td>Stream 생성 실패 또는 Transcoding 실패와 관련된 Codec Module 정보입니다.</td></tr><tr><td><code>extraInfo.sourceTrackId</code></td><td>Stream 생성 실패 또는 Transcoding 실패와 관련된 Egress Stream의 Track ID입니다.</td></tr><tr><td><code>extraInfo.parentSourceTrackId</code></td><td>Stream 생성 실패 또는 Transcoding 실패와 관련된 Ingress Stream의 Track ID입니다.</td></tr></tbody></table>

#### Security

보안상의 이유로 Control Server는 수신된 HTTP 요청의 유효성을 검사해야 할 수 있습니다. 이를 위해 Enhanced Alert Module은 `X-OME-Signature` 값을 HTTP Request Header에 추가합니다.

이때, `X-OME-Signature`는 `Server.xml` 내  `<Alert><SecretKey>`에 설정된 Secret Key를 사용하여 HMAC-SHA1 Algorithm으로 HTTP Request의 Payload를 암호화한 뒤, URL-safe (base64)로 인코딩한 값입니다.

### Response

Engine이 Closing 상태일 때, Response에 별도의 Parameter가 필요하지 않으므로 Response Payload는 무시됩니다.

```http
HTTP/1.1 200 OK
Content-Length: 0
Connection: Closed
```

## Anomaly Detection | 0.20.1.0+

Anomaly Detection은 Streaming 과정에서 발생하는 Input Stream 오류를 탐지하고, Alert Callback 또는 Stream 종료 등 후속 조치를 취할 수 있는 모듈입니다.

Anomaly Detection는 아래와 같이 `<Server><Alert><Rules>`에서 설정할 수 있습니다:

```xml
<Server>
	<Alert>
		<Rules>
			...
			<Anomaly>
				<DTSReversal>
					<CheckDuration>5</CheckDuration>
					<Count>1</Count>
					<Threshold>5</Threshold>
					<Action>TerminateStream,Alert</Action>
				</DTSReversal>
				<DTSJump>
					<Action>TerminateStream,Alert</Action>
				</DTSJump>
				<DTSDuplication>
					<Count>1</Count>
					<Action>TerminateStream,Alert</Action>
				</DTSDuplication>
				<PacketTimeout>
					<Action>TerminateStream,Alert</Action>
				</PacketTimeout>
			</Anomaly>
		</Rules>
	</Alert>
...
```

<table><thead><tr><th width="139.5555419921875">Key</th><th width="159.5555419921875" align="center">Default (Allowed)</th><th>Description</th></tr></thead><tbody><tr><td>CheckDuration</td><td align="center">10 (0-3600)</td><td><p>Action 실행 조건을 판단하기 위해, Anomaly 발생 횟수를 누적 집계하는 기준 시간입니다. </p><ul><li>단위는 초 (s)입니다.</li></ul><p><code>CheckDuration</code>으로 설정된 시간 내에 <code>Threshold</code> (아래 각 옵션마다 설명)를 초과하는 상황이 <code>Count</code> 횟수만큼 발생할 경우 <code>Action</code>이 발동됩니다.</p><ul><li>ex) <code>CheckDuration</code>이 <code>0</code>으로 설정된 경우, <code>Count</code>가 <code>1</code>이면 대기 시간 없이 즉시 탐지하지만, <code>Count</code>가 <code>2</code>이상이면 시간 구간이 없으므로 탐지가 불가능합니다.</li></ul></td></tr><tr><td>Count</td><td align="center">1  (1-65535)</td><td><p><code>CheckDuration</code>으로 설정된 시간 내에 Anomaly 횟수가 <code>Count</code>에 설정된 값보다 많이 발생하면 Anomaly로 판단합니다.</p><ul><li>단위는 회 입니다.</li></ul></td></tr><tr><td>Action</td><td align="center">N/A</td><td><p>Anomaly가 탐지된 이후에 어떤 후속 조치를 할지 지정합니다. 설정 가능한 후속 조치는 아래와 같으며, 복수로 지정할 수 있습니다.</p><ol><li><code>TerminateStream</code>: Anomaly가 감지된 <code>WebRTC</code>, <code>Ovt</code>, <code>RTMP</code>, <code>RtmpPull</code>, <code>Rtsp</code>, <code>RtspPull</code>, <code>Mpegts</code>, <code>Srt</code> 와같은 Source Type일 때, Stream을 중단합니다.</li><li><code>Alert</code>: Anomaly 감지 여부를 Alert으로 전송합니다.</li></ol></td></tr></tbody></table>

### DTSReversal 설정하기

`DTSReversal`은 Decoding Time Stamp (DTS)가 이전 값  (ms)보다 작아지거나, 증가하지 않아 재생 문제가 생길 수 있는 경우를 탐지합니다.

`DTSReversal`은 `<Server><Alert><Rules><Anomaly>`에 설정할 수 있으며, 아래는 예제입니다:

```xml
<Server>
	<Alert>
		<Rules>
		...
			<Anomaly>
				<DTSReversal>
					<CheckDuration>5</CheckDuration>	<!-- 최근 5초 동안 -->
					<Count>2</Count>	<!-- 두 번 이상 -->
					<Threshold>5</Threshold>	<!-- DTS가 5ms 이상 역전하였다면 -->
					<Action>TerminateStream,Alert</Action>	<!-- 해당 스트림을 종료하고 alert -->
				</DTSReversal>
				...
```

\= 최근 5초 동안 (`CheckDuration`) DTS가 5밀리초 이상 역전 (`Threshold`)된 횟수가 2회 이상 (`Count`)이라면 해당 Stream을 종료하고 Alert을 전송 (`Action`)합니다.

<table><thead><tr><th width="139.5555419921875">Key</th><th width="159.5555419921875" align="center">Default (Allowed)</th><th>Description</th></tr></thead><tbody><tr><td>Threshold</td><td align="center">1<br>(1-2147483647)</td><td><p>"DTS가 몇 밀리초 이상 역전해야 Anomaly로 판단하는가?"에 대한 기준입니다.</p><ul><li>단위는 밀리초 (ms)입니다.</li></ul></td></tr></tbody></table>

#### Notification 예제

```json
{
	"sourceUri": "#default#app/stream",
	"messages": [
		{
			"code": "ANOMALY_DTS_REVERSAL_DETECTED",
			"description": "DTS has been reversed by 100."
		}
	],
	"type": "ANOMALY"
}
```

### DTSJump 설정하기

`DTSJump`는 연속된 Frame 사이에 DTS가 급격히 증가하여, 재생 문제를 일으킬 수 있는 경우를 탐지합니다.

`DTSJump`는 `<Server><Alert><Rules><Anomaly>`에 설정할 수 있으며, 아래는 예제입니다:

```xml
<Server>
	<Alert>
		<Rules>
			<Anomaly>
				<DTSJump>
					<CheckDuration>5</CheckDuration>	<!-- 최근 5초 동안 -->
					<Count>2</Count>	<!-- 두 번 이상 -->
					<Threshold>1000</Threshold>	<!-- DTS가 1000ms 이상 급증하였다면 -->
					<Action>TerminateStream,Alert</Action>	<!-- 해당 스트림을 종료하고 alert -->
				</DTSJump>
				...
```

\= 최근 5초 동안 (`CheckDuration`) DTS가 1,000밀리초 이상 급증 (`Threshold`)한 횟수가 2회 이상 (`Count`)이라면 해당 Stream을 종료하고 Alert을 전송 (`Action`)합니다.

<table><thead><tr><th width="139.5555419921875">Key</th><th width="159.5555419921875" align="center">Default (Allowed)</th><th>Description</th></tr></thead><tbody><tr><td>Threshold</td><td align="center">1000<br>(1-2147483647)</td><td><p>"DTS가 몇 밀리초 이상 급증해야 Anomaly로 판단하는가?"에 대한기준입니다.</p><ul><li>단위는 밀리초 (ms)입니다.</li></ul></td></tr></tbody></table>

#### Notification 예제

```json
{
	"sourceUri": "#default#app/stream",
	"messages": [
		{
			"code": "ANOMALY_DTS_JUMP_DETECTED",
			"description": "DTS has increased significantly by 3000."
		}
	],
	"type": "ANOMALY"
}
```

### DTSDuplication 설정하기

`DTSDuplication`는 연속된 Frame의 DTS가 동일하여, 재생 문제를 일으킬 수 있는 경우를 탐지합니다.

`DTSDuplication`은 `<Server><Alert><Rules><Anomaly>`에 설정할 수 있으며, 아래는 예제입니다:

```xml
<Server>
	<Alert>
		<Rules>
			<Anomaly>
				<DTSDuplication>
					<CheckDuration>5</CheckDuration>	<!-- 최근 5초 동안 -->
					<Count>2</Count>	<!-- 두 번 이상 -->
					<Action>TerminateStream,Alert</Action>	<!-- 해당 스트림을 종료하고 alert -->
				</DTSDuplication>
				...
```

\= 최근 5초 동안 (`CheckDuration`) DTS가 동일한 횟수가 2회 이상 (`Count`)이라면 해당 Stream을 종료하고 Alert을 전송 (`Action`)합니다.

#### Notification 예제

```json
{
	"sourceUri": "#default#app/stream",
	"messages": [
		{
			"code": "ANOMALY_DTS_DUPLICATION_DETECTED",
			"description": "DTS has been duplicated 2 times."
		}
	],
	"type": "ANOMALY"
}
```

### PacketTimeout 설정하기

`PacketTimeout`은 지정한 시간 동안 Packet이 수신되지 않아, 재생 문제를 일으킬 수 있는 경우를 탐지합니다.

`PacketTimeout`은 `<Server><Alert><Rules><Anomaly>`에 설정할 수 있으며, 아래는 예제입니다:

```xml
<Server>
	<Alert>
		<Rules>
			<Anomaly>
				<PacketTimeout>
					<CheckDuration>5</CheckDuration>	<!-- 최근 5초 동안 -->
					<Count>2</Count>	<!-- 두 번 이상 -->
					<Threshold>1000</Threshold>	<!-- 패킷이 1000ms 이상 수신되지 않았다면 -->
					<Action>TerminateStream,Alert</Action>	<!-- 해당 스트림을 종료하고 alert -->
				</PacketTimeout>
				...
```

\= 최근 5초 동안 (`CheckDuration`)  Packet이 1,000밀리초 이상 수신 (`Threshold`)되지 않은 횟수가 2회 이상 (`Count`)이라면 해당 Stream을 종료하고 Alert을 전송 (`Action`)합니다.

<table><thead><tr><th width="139.5555419921875">Key</th><th width="159.5555419921875" align="center">Default (Allowed)</th><th>Description</th></tr></thead><tbody><tr><td>Threshold</td><td align="center">1500<br>(1-2147483647)</td><td><p>"Packet이 몇 밀리초 만큼 수신되지 않을 경우 Anomaly로 판단하는가?"에 대한 기준입니다.</p><ul><li>단위는 밀리초 (ms)입니다.</li></ul></td></tr></tbody></table>

{% hint style="warning" %}
`PacketTimeout` 기능이 [Origin Redudnacy의 `PacketSilenceTimeoutMs`](https://ovenmediaengine-enterprise.gitbook.io/guide/ko-kr/high-availability/origin-redundancy#packetsilencetimeoutms)와 중복되므로, Anomaly Detection 기능을 사용하는 것을 권장합니다.

* 두 설정 모두 켜져 있는 경우, 조금 더 작은 값으로 설정된 모듈이 먼저 동작합니다.
  {% endhint %}

#### Notification 예제

```json
{
	"sourceUri": "#default#app/stream",
	"messages": [
		{
			"code": "ANOMALY_PACKET_TIMEOUT_DETECTED",
			"description": "No packets have been received for 1500ms."
		}
	],
	"type": "ANOMALY"
}
```
