# oss-live

Part of **OSS**

<!-- intent-backlink:auto -->

> 💡 **Path Selection**: This skill is one implementation path for [Process media files (e.g., HLS streaming)](../../intent/oss-process-files/SKILL.md). If you're unsure which path to take, check the routing skill first.

# Object Storage Service Streaming

## Capabilities Overview

| Sub-capability | Calling Mode | Description |
|----------------|--------------|-------------|
| Manage Live Channel | Synchronous | Create, delete, and manage live channels for streaming. |
| Query Live Channel Info | Synchronous | Get information, status, and history of live channels. |
| Manage VOD Playlist | Synchronous | Generate and retrieve VOD playlists from live streams. |
| Change Live Channel Status | Synchronous | Modify the operational status of live channels. |
| Create RTMP Ingest URL | Synchronous | Generate RTMP URLs and signatures for stream ingestion. |
| Ingest RTMP Stream | Synchronous | Handle RTMP stream ingestion into the storage system. |

## API Calling Patterns

### Authentication
The primary authentication method is **OSS Signature Version 4 (HMAC-SHA256)**.

- Include the `Authorization` header in every request:
```text
  Authorization: OSS4-HMAC-SHA256 Credential=<AccessKeyId>/<date>/<region>/oss/aliyun_v4_request,Signature=<signature>
  ```
- Set credentials via environment variables:
  ```bash
  export OSS_ACCESS_KEY_ID=your_access_key_id
  export OSS_ACCESS_KEY_SECRET=your_access_key_secret
  ```
- Alternative: Signed RTMP URLs can be generated for stream ingestion without per-request signing.

### Service Endpoint (Endpoint)
APIs use bucket-specific endpoints with region patterns:

- Base pattern: `https://{bucket}.{region}.aliyuncs.com`
- Common regions: `cn-hangzhou`, `cn-shanghai`, `cn-beijing`
- Example: `https://examplebucket.oss-cn-hangzhou.aliyuncs.com`

### Synchronous API Pattern
All OSS Live Channel operations follow a synchronous request-response flow:

1. Construct a properly signed HTTP request with required headers (`Date`, `Host`, `Authorization`)
2. Send the request to the bucket-specific endpoint with query parameters (e.g., `?live`, `?vod`)
3. Receive an immediate XML or M3U8 response (or empty body for mutations like DELETE)
4. Parse the response or check the HTTP status code (200/204 = success)

No polling or async task IDs are used — each operation completes in a single round trip.

## Parameter Reference

### Manage Live Channel

| Parameter | Type | Required | Default | Constraints | Description |
|-----------|------|----------|---------|-------------|-------------|
| ChannelName | String | Yes | — | No `/` allowed | Name of the LiveChannel to create |
| Status | Enumerated string | No | enabled | `enabled`, `disabled` | Operational status of the channel |
| Type | Enumerated string | Yes | — | `HLS` | Format for storing uploaded data |
| FragDuration | String | No | 5 | [1, 100] seconds | Duration of each TS file |
| FragCount | String | No | 3 | [1, 100] | Number of TS files in m3u8 |
| PlaylistName | String | No | playlist.m3u8 | Must end with `.m3u8` | Name of generated m3u8 file |
| Interval | NUMERIC | Yes (if Snapshot) | — | [1, 100] seconds | Snapshot interval |

### Manage VOD Playlist

| Parameter | Type | Required | Default | Constraints | Description |
|-----------|------|----------|---------|-------------|-------------|
| ChannelName | string | Yes | — | — | Name of existing LiveChannel |
| StartTime | integer | Yes | — | Unix timestamp | Start time of query range |
| EndTime | integer | Yes | — | > StartTime, < 1 day diff | End time of query range |
| PlaylistName | String | Yes (PostVodPlaylist) | — | Must end with `.m3u8` | Output playlist filename |

### Change Live Channel Status

| Parameter | Type | Required | Default | Constraints | Description |
|-----------|------|----------|---------|-------------|-------------|
| status | string | Yes | — | `enabled`, `disabled` | New status for the LiveChannel |

### Create RTMP Ingest URL

| Parameter | Type | Required | Default | Constraints | Description |
|-----------|------|----------|---------|-------------|-------------|
| OSSAccessKeyId | string | Yes | — | — | Same as OSS AccessKey ID |
| Expires | integer | Yes | — | Unix timestamp | Expiration time in seconds |
| Signature | string | Yes | — | — | Computed signature string |
| playlistName | string | No | — | — | Name of generated M3U8 file |

## Code Examples

### Create Live Channel - Python - cn-hangzhou

```python
# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider

# Obtain access credentials from environment variables. Before you run this sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are set.
auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider())
# Specify the endpoint for the bucket's region. For example, if the bucket is in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com.
# Specify the bucket name. Example: examplebucket.
bucket = oss2.Bucket(auth, 'https://oss-cn-hangzhou.aliyuncs.com', 'examplebucket')
# Specify the LiveChannel name. Example: test-channel.
channel_name = "test-channel"
channel_cfg = oss2.models.LiveChannelInfo(target = oss2.models.LiveChannelInfoTarget())
channel = bucket.create_live_channel(channel_name, channel_cfg)
publish_url = channel.publish_url
# Generate a signed URL for RTMP stream ingest and set the expiration time to 3,600 seconds.
signed_publish_url = bucket.sign_rtmp_url(channel_name, "playlist.m3u8", 3600)
# Print the unsigned ingest URL.
print('publish_url='+publish_url)
# Print the signed ingest URL.
print('signed_publish_url='+signed_publish_url)
```

### Create Live Channel - Java - cn-hangzhou

```java
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import java.util.List;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.common.comm.SignVersion;

public class Demo {

    public static void main(String[] args) throws Exception {
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // Obtain access credentials from environment variables. Before you run this sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are set.
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // Specify the bucket name. Example: examplebucket.
        String bucketName = "examplebucket";
        // Specify the LiveChannel name.
        String liveChannelName = "yourLiveChannelName";
        // Specify the region where the bucket is located. For example, if the bucket is in the China (Hangzhou) region, set the region to cn-hangzhou.
        String region = "cn-hangzhou";

        // Create an OSSClient instance.
        // Call the shutdown method to release resources when you no longer need the OSSClient instance.
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);        
        OSS ossClient = OSSClientBuilder.create()
        .endpoint(endpoint)
        .credentialsProvider(credentialsProvider)
        .clientConfiguration(clientBuilderConfiguration)
        .region(region)               
        .build();

        try {
            CreateLiveChannelRequest request = new CreateLiveChannelRequest(bucketName,
                    liveChannelName, "desc", LiveChannelStatus.Enabled, new LiveChannelTarget());
            CreateLiveChannelResult result = ossClient.createLiveChannel(request);

            // Obtain the ingest URLs.
            List<String> publishUrls = result.getPublishUrls();
            for (String item : publishUrls) {
                // Obtain the ingest URL that does not contain signature information.
                System.out.println(item);

                // Obtain the ingest URL that contains signature information.
                LiveChannelInfo liveChannelInfo = ossClient.getLiveChannelInfo(bucketName, liveChannelName);
                // The expires parameter specifies the expiration time as a UNIX timestamp. In this example, the expiration time is set to one hour from the current time.
                long expires = System.currentTimeMillis() / 1000 + 3600;
                // The playlistName parameter specifies the name passed to the CreateLiveChannel operation. If you do not specify this parameter, the system uses the default value playlist.m3u8. You can also call the GetLiveChannelInfo operation to obtain this name.
                String signRtmpUrl = ossClient.generateRtmpUri(bucketName, liveChannelName, liveChannelInfo.getTarget().getPlaylistName(), expires);
                System.out.println(signRtmpUrl);
            }

            // Obtain the playback URLs.
            List<String> playUrls = result.getPlayUrls();
            for (String item : playUrls) {
                System.out.println(item);
            }
        } catch (OSSException oe) {
            oe.printStackTrace();
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}
```

### Push Stream with FFmpeg - Bash - All Regions

```bash
ffmpeg -i 1.flv -c copy -f flv "rtmp://examplebucket.oss-cn-hangzhou.aliyuncs.com/live/test-channel?playlistName=playlist.m3u8&OSSAccessKeyId=LTAI********&Expires=1688543369&Signature=eqK8z0ZTSwznP7fkELy0ckt0Iv***"
```

### List Live Channels - HTTP - cn-hangzhou

```http
GET /?live&max-keys=1 HTTP/1.1
Date: Thu, 25 Aug 2016 07:50:09 GMT
Host: test-bucket.oss-cn-hangzhou.aliyuncs.com
Authorization: OSS4-HMAC-SHA256 Credential=LTAI********************/20250417/cn-hangzhou/oss/aliyun_v4_request,Signature=a7c3554c729d71929e0b84489addee6b2e8d5cb48595adfc51868c299c0c218e
```

### Get VOD Playlist - HTTP - cn-hangzhou

```http
GET /test-channel?vod&endTime=1472020226&startTime=1472020031 HTTP/1.1
Date: Thu, 25 Aug 2016 07:13:26 GMT
Host: test-bucket.oss-cn-hangzhou.aliyuncs.com
Authorization: OSS4-HMAC-SHA256 Credential=LTAI********************/20250417/cn-hangzhou/oss/aliyun_v4_request,Signature=a7c3554c729d71929e0b84489addee6b2e8d5cb48595adfc51868c299c0c218e
```

### Delete Live Channel - HTTP - cn-hangzhou

```http
DELETE /test-channel? live HTTP/1.1
Date: Thu, 25 Aug 2016 07:32:26 GMT
Host: test-bucket.oss-cn-hangzhou.aliyuncs.com
Authorization: OSS4-HMAC-SHA256 Credential=LTAI********************/20250417/cn-hangzhou/oss/aliyun_v4_request,Signature=a7c3554c729d71929e0b84489addee6b2e8d5cb48595adfc51868c299c0c218e
```

## Response Format

```xml
<CreateLiveChannelResult>
  <PublishUrls>
    <Url>rtmp://test-bucket.oss-cn-hangzhou.aliyuncs.com/live/test-channel</Url>
  </PublishUrls>
  <PlayUrls>
    <Url>http://test-bucket.oss-cn-hangzhou.aliyuncs.com/test-channel/playlist.m3u8</Url>
  </PlayUrls>
</CreateLiveChannelResult>
```

**Key Fields**:
- `CreateLiveChannelResult.PublishUrls.Url` — RTMP URL for stream ingestion
- `CreateLiveChannelResult.PlayUrls.Url` — HTTP URL for HLS playback

### VOD Playlist Response Format
```text
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-TARGETDURATION:13
#EXTINF:7.120,
1543895706266.ts
#EXTINF:5.840,
1543895706323.ts
#EXT-X-ENDLIST
```

## Error Handling

| Error Code | Description | Recommended Action |
|------------|-------------|-------------------|
| 400 | The request failed because a client is currently ingesting streams into the LiveChannel. | Wait until streaming stops before deleting or modifying the channel. |
| 400 | Invalid request parameters (e.g., bad timestamps, missing status). | Validate all parameters against constraints; ensure StartTime < EndTime. |
| 403 | Access denied. Check your permissions or authorization header. | Verify AccessKey permissions and signature calculation. |
| 404 | Bucket or LiveChannel not found. | Confirm bucket name, region, and channel name spelling. |
| 409 | A LiveChannel with the same name already exists. | Use a unique channel name or delete the existing one first. |

## Environment Requirements

- **Python**: `pip install oss2>=2.0.0`
- **Java**: Maven dependency `com.aliyun.oss:aliyun-sdk-java-oss:>=3.10.0`
- Set environment variables:
  ```bash
  export OSS_ACCESS_KEY_ID=your_access_key_id
  export OSS_ACCESS_KEY_SECRET=your_access_key_secret
  ```

## FAQ

Q: How do I generate a signed RTMP URL for secure stream ingestion?
A: Use the SDK method `sign_rtmp_url()` (Python) or `generateRtmpUri()` (Java) with channel name, playlist name, and expiration time. This returns a URL with `OSSAccessKeyId`, `Expires`, and `Signature` parameters.

Q: Why am I getting a 400 error when trying to delete a LiveChannel?
A: The channel cannot be deleted while a client is actively ingesting a stream. Stop the stream first, wait for disconnection, then retry deletion.

Q: What is the maximum duration for a VOD playlist query?
A: The time range between `StartTime` and `EndTime` must be less than one day (86,400 seconds).

Q: Can I change a LiveChannel's configuration after creation?
A: No, you must delete and recreate the channel with new settings. However, you can change its status (enabled/disabled) using `PutLiveChannelStatus`.

Q: Are the generated TS files and playlists automatically deleted when I delete a LiveChannel?
A: No, all generated objects (TS segments, m3u8 playlists) remain in the bucket and must be deleted separately if no longer needed.

## Pricing & Billing

### Billing Model
All operations are billed **per request**, with additional charges for data transfer and storage.

### Price Reference

| Tier / Operation | Input Price | Output Price | Other Fees |
|------------------|-------------|--------------|------------|
| LiveChannel creation | 0.001 / | 0.001 / | Storage and traffic fees apply |
| Standard requests (list, info, status, history, VOD) | 0.0001 / | 0.0001 / | — |
| RTMP ingest | 0.0001 /MB | 0.0002 /MB | 0.001 /hour for streaming duration |
| LiveChannel status change | 0.0001 / | — | — |

### Free Tier
- 100 free LiveChannel creations per month
- 1000 free standard requests per month
- 10 GB free upload traffic per month

### Usage Limits
- Maximum 100 LiveChannels per bucket
- 100 QPS per bucket for listing operations
- 100 Mbps max ingest rate per LiveChannel
- VOD playlist time range < 1 day

### Billing Notes
- Deleting a LiveChannel does not remove stored TS files or playlists; storage fees continue to accrue.
- Stream duration is billed per minute (minimum 1 minute).
- High-frequency snapshot operations are billed per trigger event.