# AMF0 Message Insertion

Live Stream을 RTMP 프로토콜로 다른 시스템에 재스트리밍 (Push Publishing)할 때, AMF0 message를 삽입 할 수 있습니다. 이 기능을 활용하여 자막 삽입, 광고 Maker 삽입과 같은 message를 다른 시스템에 전달 할 수 있습니다. message를 삽입하는 방법은 아래와 같습니다.

* RTMP Provider를 통해 입력받은 Media Source에 message가 포함되어 있는 경우 자동으로 삽입 됩니다.
* OvenMediaEngine의 Send Event API를 사용하여 동적으로, XML 설정을 통해 지속적으로 message를 삽입 할 수 있습니다.

## onTextData

### REST API로 onTextData 삽입하기 | 0.17.3.0+

`onTextData` message는 자막 삽입, 광고 마커 삽입 등 다양한 목적으로 사용되고 있습니다.

#### API Interface

**Request**

<details>

<summary><mark style="color:blue;">POST</mark> /v1/vhosts/{vhost}/apps/{app}/streams/{stream}:sendEvent</summary>

**Header**

```http
Authorization: Basic {credentials}

# Authorization
Credentials for HTTP Basic Authentication created with <AccessToken>
```

**Body**

```json
{
  "eventFormat": "amf",
  "events":[
    {
      "amfType": "onTextData",
      "data": {
        "key1": "value",  // String Type
        "key2": 354.1,    // Number Type [Double]
        "key3": true     // Boolean Type [true | false]
      }
    }
  ]
}
```

</details>

<details>

<summary><mark style="color:blue;">POST</mark> /v1/vhosts/{vhost}/apps/{app}/streams/{stream}:sendEvents</summary>

**Header**

```http
Authorization: Basic {credentials}

# Authorization
Credentials for HTTP Basic Authentication created with <AccessToken>
```

**Body**

```json
[
  {
    "eventFormat": "id3v2",
    "eventType": "video", // "eventTarget": "video" is same
    "events":[
      {
        "frameType": "TXXX",
        "info": "AirenSoft",
        "data": "OvenMediaEngine"
      },
      {
        "frameType": "TIT2",
        "data": "OvenMediaEngine 123"
      }
    ]
  },
  {
    "eventFormat": "amf",
    "events":[
      {
        "amfType": "onTextData",
        "data": {
          "key1": "value",  // String Type
          "key2": 354.1,    // Number Type [Double]
          "key3": true     // Boolean Type [true | false]
        }
      }
    ]
  }
]
```

</details>

**Responses**

<details>

<summary><mark style="color:blue;">200</mark> Ok</summary>

The request has succeeded

**Header**

```http
Content-Type: application/json
```

**Body**

```json
{
    "message": "OK",
    "statusCode": 200
}
```

</details>

<details>

<summary><mark style="color:red;">400</mark> Bad Request</summary>

Invalid request. Body is not a Json Object or does not have a required value

</details>

<details>

<summary><mark style="color:red;">401</mark> Unauthorized</summary>

Authentication required

**Header**

```http
WWW-Authenticate: Basic realm=”OvenMediaEngine”
```

**Body**

```json
{
    "message": "[HTTP] Authorization header is required to call API (401)",
    "statusCode": 401
}
```

</details>

<details>

<summary><mark style="color:red;">404</mark> Not Found</summary>

The given vhost name or application name could not be found.

**Body**

```json
{
    "message": "[HTTP] Could not find the application: [default/app2] (404)",
    "statusCode": 404
}
```

</details>

### XML설정으로 onTextData 삽입하기 | 0.18.2.0+

지속적인 `onTextData` message 삽입이 필요한 경우, XML 설정을 통해 동작을 구성할 수 있습니다. `onTextData` message 삽입 Event를 정의한 XML파일을 생성하고 `Server.xml`에서 `EventGenerator`를 활성화 합니다.

#### Configuration 예제

**Server.xml:** `<Application><EventGenerator>`를 추가하여 `onTextData` message 삽입을 위한 `EventGenerator`기능을 활성화 할 수 있습니다.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<Server version="8">
  ...
  <VirtualHosts>
    <VirtualHost>
      <Applications>
        <Application>
          ...
          <EventGenerator>
            <Enable>true</Enable>
            <Path>events/send_event_info.xml</Path>
          </EventGenerator>
        </Application>
      </Applications>
    </VirtualHost>
  </VirtualHosts>
</Server>
```

<table><thead><tr><th width="144">Element</th><th>Description</th></tr></thead><tbody><tr><td><code>&#x3C;Enable></code></td><td><p><code>true</code> 또는 <code>false</code>로 활성화 여부를 설정합니다.</p><ul><li><mark style="color:yellow;">Default: <code>false</code></mark></li></ul></td></tr><tr><td><code>&#x3C;Path></code></td><td>세부 <code>onTextData</code> message 삽입을 정의한 XML 파일의 경로를 설정합니다. 상대 경로를 지정하면 <code>Server.xml</code> 파일이 있는 디렉토리가 기준이 됩니다.</td></tr></tbody></table>

**onTextData message 삽입을 정의한 XML:** `Server.xml`에서 정의한 경로에 `onTextData` message 삽입를 정의한 XML파일을 생성합니다. 아래 예제의 경우 `send_event_info.xml`입니다.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<EventInfo>
  <Event>
    <Enable>true</Enable>
    <SourceStreamName>stream*</SourceStreamName>
    <Interval>2000</Interval>
    <EventFormat>amf</EventFormat>
    <EventType>video</EventType>
    <Values>
      <AmfType>onTextData</AmfType>
      <Data>
        <key1 type="string">value</key1>    // String Type
        <key2 type="double">354.1</key2>    // Number Type [Double]
        <key3 type="boolean">true</key3>    // Boolean Type [true | false]
        <key4>${EpochTime}</key4>
      </Data>
    </Values>
  </Event>
</EventInfo>
```

<table><thead><tr><th width="239">Parameter</th><th>Description</th></tr></thead><tbody><tr><td><code>&#x3C;Enable></code></td><td><p><code>true</code> 또는 <code>false</code>로 활성화 여부를 설정합니다.</p><ul><li><mark style="color:yellow;">Default: <code>false</code></mark></li></ul></td></tr><tr><td><code>&#x3C;SourceStreamName></code></td><td><p><code>onTextData</code> message를 삽입할 Stream의 이름을 지정합니다.</p><ul><li><mark style="color:yellow;">패턴 매칭을 위한 Wildcard (<code>*</code>)를 지원합니다.</mark></li></ul></td></tr><tr><td><code>&#x3C;Interval></code></td><td>Event 발생 주기를 밀리초 (ms) 단위로 설정합니다.</td></tr><tr><td><code>&#x3C;EventFormat></code></td><td>Event 포맷을 지정합니다: <code>amf</code> 형식 사용.</td></tr><tr><td><code>&#x3C;EventType></code></td><td><p>Event 타입을 지정합니다.</p><ul><li><mark style="color:yellow;">Default: <code>video</code></mark></li></ul></td></tr><tr><td><code>&#x3C;Values></code></td><td>Event 데이터 값을 포함합니다.</td></tr><tr><td><code>&#x3C;Values>&#x3C;amfType></code></td><td>AMF0 message 타입을 지정합니다: <code>onTextData</code> 형식 사용.</td></tr><tr><td><code>&#x3C;Values>&#x3C;Data></code></td><td><p>실제 전송할 데이터의 배열을 지정합니다.</p><ul><li><code>key</code> 태그를 사용할 수 있으며, Type Attribute가지정되지 않은 경우 기본 String으로 판단합니다.</li><li><code>${EpochTime}</code>을 사용하여 밀리초 단위로 구성된 서버의 현재 Epoch Time으로 대체해서 전송할 수 있는 Macro를 지원합니다 (예시: 1747147513056).</li></ul></td></tr></tbody></table>

{% hint style="info" %}
이벤트 정의 XML 파일의 내용을 변경하면 OvenMediaEngine을 재시작하지 않아도 변경 사항이 바로 적용됩니다.
{% endhint %}

### AMF0.onTextData 구조

AMF0로 인코딩 된 `onTextData` message payload의 예제입니다. Common Object (ECMA Array) 는 Key와 Value 리스트로 구성되며, Value 타입은 String, Number, Boolean 입니다.

```
string-maker "onTextData"         // Command Name ECMA Array: 
ecma-array-maker
"key1" string-maker "value"       // String Type
"key2" number-maker 354.1         // Number Type [Double]
"key3" boolean-maker 1            // Boolean Type [1 | 0]
...
object-end-marker
```

## onUserDataEvent

### REST API로 onUserDataEvent 삽입하기 | 0.19.1.1+

`onUserDataEvent` message는 자막 삽입, 광고 마커 삽입 등 다양한 목적으로 사용되고 있습니다.

#### API Interface

**Request**

<details>

<summary><mark style="color:blue;">POST</mark> /v1/vhosts/{vhost}/apps/{app}/streams/{stream}:sendEvent</summary>

**Header**

```http
Authorization: Basic {credentials}

# Authorization
Credentials for HTTP Basic Authentication created with <AccessToken>
```

**Body**

```json
[
    {
        "eventFormat": "amf",
        "events": [
            {
                "amfType": "onUserDataEvent",
                "data": {
                    "key1": "value",    // String Type
                    "key2": 354.1       // Number Type [Double]
                    "key3": true        // Boolean Type [true | false]
                }
            }
        ]
    }

```

</details>

<details>

<summary><mark style="color:blue;">POST</mark> /v1/vhosts/{vhost}/apps/{app}/streams/{stream}:sendEvents</summary>

**Header**

```http
Authorization: Basic {credentials}

# Authorization
Credentials for HTTP Basic Authentication created with <AccessToken>
```

**Body**

```json
[
    {
        "eventFormat": "amf",
        "events": [
            {
                "amfType": "onUserDataEvent",
                "data": "<XMLTag>{\"time\":\"2026-09-09T02:07:42.934Z\",\"program\":\"adsection\"}<\/XMLTag>"
            }
        ]
    }
]
```

</details>

**Responses**

<details>

<summary><mark style="color:blue;">200</mark> Ok</summary>

The request has succeeded

**Header**

```http
Content-Type: application/json
```

**Body**

```json
{
    "message": "OK",
    "statusCode": 200
}
```

</details>

<details>

<summary><mark style="color:red;">400</mark> Bad Request</summary>

Invalid request. Body is not a JSON object or does not have a required value

</details>

<details>

<summary><mark style="color:red;">401</mark> Unauthorized</summary>

Authentication required

**Header**

```http
WWW-Authenticate: Basic realm=”OvenMediaEngine”
```

**Body**

```json
{
    "message": "[HTTP] Authorization header is required to call API (401)",
    "statusCode": 401
}
```

</details>

<details>

<summary><mark style="color:red;">404</mark> Not Found</summary>

The given vhost name or application name could not be found.

**Body**

```json
{
    "message": "[HTTP] Could not find the application: [default/app2] (404)",
    "statusCode": 404
}
```

</details>

### XML설정으로 onUserDataEvent 삽입하기 | 0.19.1.1+

지속적인 `onUserDataEvent` message 삽입이 필요한 경우, XML 설정을 통해 동작을 구성할 수 있습니다. `onUserDataEvent` message 삽입 Event를 정의한 XML파일을 생성하고 `Server.xml`에서 `EventGenerator`를 활성화 합니다.

#### Configuration 예제

**Server.xml:** `<Application><EventGenerator>`를 추가하여 `onUserDataEvent` message 삽입을 위한 `EventGenerator`기능을 활성화 할 수 있습니다.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<Server version="8">
  ...
  <VirtualHosts>
    <VirtualHost>
      <Applications>
        <Application>
          ...
          <EventGenerator>
            <Enable>true</Enable>
            <Path>events/send_event_info.xml</Path>
          </EventGenerator>
        </Application>
      </Applications>
    </VirtualHost>
  </VirtualHosts>
</Server>
```

<table><thead><tr><th width="144">Element</th><th width="100">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>&#x3C;Enable></code></td><td>Y</td><td><p><code>true</code> 또는 <code>false</code>로 활성화 여부를 설정합니다.</p><ul><li><mark style="color:yellow;">Default: <code>false</code></mark></li></ul></td></tr><tr><td><code>&#x3C;Path></code></td><td>Y</td><td>세부 <code>onUserDataEvent</code> message 삽입을 정의한 XML 파일의 경로를 설정합니다. 상대 경로를 지정하면 <code>Server.xml</code> 파일이 있는 디렉토리가 기준이 됩니다.</td></tr></tbody></table>

**onUserDataEvent message 삽입을 정의한 XML:** `Server.xml`에서 정의한 경로에 `onTextData` message 삽입를 정의한 XML파일을 생성합니다. 아래 예제의 경우 `send_event_info.xml`입니다.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<EventInfo>
  <!-- Simple -->
  <Event>
    <SourceStreamName>schedule*</SourceStreamName>
    <Interval>1000</Interval>
    <EventFormat>amf</EventFormat>
    <Values>
      <AmfType>onUserDataEvent</AmfType>
      <Data>
         <key1>value</key1>,    // String Type, Default
         <key1 type="string">value</key1>,    // String Type
         <key2 type="double">354.1</key2>,    // Number Type [Double]
         <key3 type="boolean">true</key3>      // Boolean Type [true | false]
      </Data>
    </Values>
  </Event>
  
  <!-- Single value data format below (Example: inserting XML data) --> 
  <Event>
    <SourceStreamName>schedule*</SourceStreamName>
    <Interval>1000</Interval>
    <EventFormat>amf</EventFormat>
    <Values>
      <AmfType>onUserDataEvent</AmfType>
      <Data><![CDATA[<XMLTag>{"json":"value"}</XMLTag>]]></Data>
    </Values>
  </Event>
</EventInfo>
```

<table><thead><tr><th width="239">Parameter</th><th>Description</th></tr></thead><tbody><tr><td><code>&#x3C;SourceStreamName></code></td><td><p><code>onUserDataEvent</code> message를 삽입할 Stream의 이름을 지정합니다.</p><ul><li><mark style="color:yellow;">패턴 매칭을 위한 Wildcard (<code>*</code>)를 지원합니다.</mark></li></ul></td></tr><tr><td><code>&#x3C;Interval></code></td><td>Event 발생 주기를 밀리초 (ms) 단위로 설정합니다.</td></tr><tr><td><code>&#x3C;EventFormat></code></td><td>Event 포맷을 지정합니다: <code>amf</code> 형식 사용.</td></tr><tr><td><code>&#x3C;Values></code></td><td>Event 데이터 값을 포함합니다.</td></tr><tr><td><code>&#x3C;Values>&#x3C;amfType></code></td><td>AMF0 message 타입을 지정합니다: <code>onUserDataEvent</code> 형식 사용.</td></tr><tr><td><code>&#x3C;Values>&#x3C;Data></code></td><td><p>실제 전송할 데이터의 배열을 지정합니다.</p><ul><li><code>key</code> 태그를 사용할 수 있으며, Type Attribute가지정되지 않은 경우 기본 String으로 판단합니다.</li><li><code>${EpochTime}</code>을 사용하여 밀리초 단위로 구성된 서버의 현재 Epoch Time으로 대체해서 전송할 수 있는 Macro를 지원합니다 (예시: 1747147513056).</li></ul></td></tr></tbody></table>

{% hint style="info" %}
이벤트 정의 XML 파일의 내용을 변경하면 OvenMediaEngine을 재시작하지 않아도 변경 사항이 바로 적용됩니다.
{% endhint %}

### AMF0.onUserDataEvent 구조

AMF0로 인코딩 된 `onUserDataEvent` message payload의 예제입니다. Common Object (ECMA Array) 또는 Single Value 형태로 구성되며, Value 타입은 String, Number, Boolean 입니다.

```
[KV Array Form]

string-maker "onUserDataEvent"      // Command Name ECMA Array: 
ecma-array-maker
"key1" string-maker "value"    // String Type
"key2" number-maker 354.1      // Number Type [Double]
"key3" boolean-maker 1         // Boolean Type [1 | 0]
...
object-end-master

[Single Value Form]

string-maker "onUserDataEvent"     // Command Name ECMA Array: 
[string|number-boolean]-maker "value"  // String Type | Number Type [Double] | Boolean Type [1 | 0]
```
