This document walks through two end-to-end demos to demonstrate best practices for an agent to access the Alibaba Cloud ApsaraVideo VOD service using the llms.txt index.
Ensure you have read the getting started guide for agents and understand the basic structure of llms.txt.
If you have not installed a Coding Agent, refer to appendix: Coding Agent selection and self-check.
Agent workflow for using llms.txt
This section outlines the workflow and division of labor between the developer and the Agent. This provides the foundation for the two subsequent demos, where the Key Design Decisions table in each demo shows this methodology applied to a specific scenario.
Division of roles: developer vs. Agent
The following table details the division of responsibilities. The developer expresses requirements, prepares the environment, and accepts the results, while the Agent handles document retrieval, solution design, and code generation.
Phase | Developer | Agent |
Requirement initiation | Describes requirements in natural language. | - |
Document retrieval | - | Reads the |
Document understanding | - | Fetches detailed documentation to extract request/response parameters, code samples, and important notes. |
Solution design | Confirms or adjusts the solution. | Proposes an implementation solution based on documentation and explains the technology choices. |
Code generation | - | Generates runnable code that includes error handling. |
Environment configuration | Configures the AccessKey, installs dependencies, and sets up the console. | Provides commands and configuration guidance. |
Execution and verification | Runs the code and confirms the results. | Explains the output and troubleshoots issues. |
Agent internal workflow
The Agent processes requirements internally in four sequential phases. The output of each phase is the input for the next.
Phase 1: Read the llms.txt index
Loads the entire ~250-line index file in one operation to perform the following three tasks:
Parse the
Quick startsection to map scenarios to document paths.Extract the
Common mistakes to avoidsection to use as strict constraints for subsequent code generation.Determines the document topology, including primary modules and submodules.
Phase 2: Match scenarios and locate documentation
Match requirement keywords with scenario titles in the
Quick startsection.If a scenario matches, use its corresponding document path directly.
If no scenario matches, scan the module index to find the one to three most relevant sub-documents.
Construct the URL: BASE_URL + url_encode(relative_path).
Phase 3: Fetch documents and extract information
Extract the following elements from sub-documents as input for code generation: API name, request/response parameters, code samples, QPS limits, error codes, region restrictions, and other notes.
Phase 4: Code generation
Before generating code, the Agent performs a self-check against the Common mistakes to avoid checklist:
If a primary account AccessKey is used, use a RAM user instead.
If status polling is implemented, switch to event notification.
If a URL is not encoded, call
url_encode.If a new credential is created for each request, reuse and refresh the
Credentialobject instead.
The Agent also adds QPS backoff and asynchronous processing logic to the final code.
URL construction rules
The index file uses relative paths to reference sub-documents. The Agent must convert these to absolute URLs to fetch them.
Base URL: https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/vod/llms/
Document URL = Base URL + URL encoding(relative path, with the leading "./" removed)
Example:
In llms.txt: [server-side upload](./媒体上传/服务端上传.md)
Full URL: Base URL + %E5%AA%92%E4%BD%93%E4%B8%8A%E4%BC%A0/%E6%9C%8D%E5%8A%A1%E7%AB%AF%E4%B8%8A%E4%BC%A0.mdEnd-to-end demos
This module provides two end-to-end demos for the server-side and client-side. The PlayURL returned by the GetPlayInfo operation links the two sides to create a complete, closed-loop workflow.
Prerequisites
Step | Location | Actions |
1 | Alibaba Cloud Console | Activate the ApsaraVideo VOD service |
2 | RAM Console | Create a RAM user, grant the |
3 | ApsaraVideo VOD Console | Configure a transcoding template group (record the TemplateGroupId) |
4 | ApsaraVideo VOD Console | Configure the HTTP callback URL (Configuration Management > Callback Settings) |
5 | Local terminal |
|
6 | Local terminal | Set the |
Server-side demo: Batch upload, transcode, and get playback URLs
This demo shows how an Agent uses the llms.txt index to build a complete server-side workflow, including batch URL upload, automatic transcoding by specifying a transcoding template group during upload and tracking progress with event notifications, and getting playback URLs after transcoding is complete.
Prompt submitted to the agent
Please use the llms.txt document (https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/vod/llms/llms.txt) to implement a complete demo workflow in Python for ApsaraVideo VOD, including batch upload, automatic transcoding, and getting playback URLs.
Specific requirements:
1. Batch upload a set of video files (provided as a list of public URLs) to ApsaraVideo VOD.
2. Automatically trigger transcoding after the upload is complete by using a specified transcoding template group.
3. After transcoding is complete, get the playback URLs for each video definition.
4. An HTTP callback service is required to receive event notifications.Agent execution process
Phase 1: Read llms.txt to match scenarios
The Agent matches scenarios and constraints in the index as follows:
Quick start keywords → Matched document path:
"Batch URL upload" → media-upload/url-based-upload.md
"Receive async event notifications" → event-notification/event-notification_2.md
"Get playback URL for frontend" → api-reference/get-playback-url.md
"Python SDK initialization" → api-reference/initialization_2.md
"Auto-transcode on upload" → media-processing/workflow.md
Common mistakes matched:
#1 Do not use a root account AccessKey #3 Do not poll for status #5 URL must be encoded #6 Use QPS backoffPhase 2: Load detailed documentation on demand
Document | Purpose |
| UploadMediaByURL parameters and limitations |
| Callback mechanism and event types |
| GetPlayInfo parameters and response structure |
| Python SDK initialization method |
| Mechanism for automatic transcoding on upload by specifying a template group |
Phase 3: Extract key information
Batch upload: UploadMediaByURL
- Asynchronous, only in China (Shanghai), max 20 URLs per request
- URLs must be URL-encoded
- Can specify TemplateGroupId → Automatic transcoding after upload
Playback URL: GetPlayInfo
- Prerequisite: Video Status=Normal (after transcoding is complete)
- Returns: PlayInfoList containing PlayURL for each definition
Event notification: HTTP POST callback
- UploadByURLComplete → Upload complete
- StreamTranscodeComplete → Single definition transcoding complete (earliest playable state)
- TranscodeComplete → All transcoding complete
- Callback timeout is 5 seconds, with a maximum of 3 retriesPhase 4: Generate code
The Agent generates the core code based on the information above.
Core code output by the agent
Batch upload (key logic): Reads the credential from an environment variable and enforces encoding for all URLs.
# Initialize - Read AK from environment variables, do not hardcode (Common mistake #1)
client = AcsClient(region_id='cn-shanghai', credential=AccessKeyCredential(
os.environ['ALIBABA_CLOUD_ACCESS_KEY_ID'],
os.environ['ALIBABA_CLOUD_ACCESS_KEY_SECRET']
))
# Batch URL upload + specify transcoding template group (auto-transcode after upload)
request = UploadMediaByURLRequest()
request.set_UploadURLs(','.join([urllib.parse.quote(url, safe='') for url in urls])) # URLs must be encoded!
request.set_UploadMetadatas(json.dumps([{'SourceURL': urllib.parse.quote(u, safe=''), 'Title': f'Video{i}'} for i, u in enumerate(urls)]))
request.set_TemplateGroupId('your_template_group_id') # Key: Specify this to auto-transcode after upload
response = json.loads(client.do_action_with_exception(request))
# Returns a list of JobIds. Track progress via event notifications.HTTP callback service (key logic): Immediately returns a 200 status to prevent server-side retries.
class CallbackHandler(BaseHTTPRequestHandler):
def do_POST(self):
body = json.loads(self.rfile.read(int(self.headers['Content-Length'])))
self.send_response(200) # Must return 200 immediately; retry is triggered after 5s timeout
self.end_headers()
if body['EventType'] == 'UploadByURLComplete' and body['Status'] == 'success':
print(f"Upload complete: VideoId={body['VideoId']}, waiting for transcoding...")
elif body['EventType'] == 'TranscodeComplete' and body['Status'] == 'success':
# All transcodings complete -> Get playback URLs
play_info = get_play_info(body['VideoId'])
for stream in play_info['PlayInfoList']['PlayInfo']:
print(f" [{stream['Definition']}] {stream['PlayURL']}")Get playback URL (key logic):
request = GetPlayInfoRequest()
request.set_VideoId(video_id)
request.set_Formats('mp4,m3u8')
request.set_AuthTimeout(3600) # URL is valid for 1 hour
response = json.loads(client.do_action_with_exception(request))
# response['PlayInfoList']['PlayInfo'] → playback URLs for each definitionExecution results
Submitting batch upload:
$ python vod_batch_upload.py
[1/2] Initializing VOD client... ✓ (region: cn-shanghai)
[2/2] Submitting batch upload job (3 videos)... ✓
RequestId: 25818875-5F78-4AF6-D7393642CA58****
JobId: ad90a501b1b9**** ← sample1.mp4
JobId: bd81b612c2c8**** ← sample2.mp4
JobId: ce72c723d3d9**** ← sample3.mp4
Subsequent steps are triggered automatically by event notifications:
UploadByURLComplete → Auto Transcode → TranscodeComplete → GetPlayInfoCallback service receives events:
$ python callback_server.py
Callback service started: http://0.0.0.0:8080 | Waiting for callbacks...
[UploadByURLComplete] VideoId=93ab850b**** | Status=success
→ Upload complete, waiting for auto-transcoding...
[StreamTranscodeComplete] VideoId=93ab850b**** | Status=success
→ LD definition transcoding complete (ready for playback)
[TranscodeComplete] VideoId=93ab850b**** | Status=success
→ All transcodings complete, getting playback URLs:
[LD] https://vod.example.com/****/sample1-ld.mp4?auth_key=****
[SD] https://vod.example.com/****/sample1-sd.mp4?auth_key=****
[HD] https://vod.example.com/****/sample1-hd.mp4?auth_key=****Agent document retrieval visualization
Prompt: "Batch upload + transcode + playback"
│
▼
┌── llms.txt (Quick start matching + Common mistakes constraints) ──┐
│ ✓ "Batch URL upload" → media-upload/url-based-upload.md │
│ ✓ "Event notification" → event-notification/event-notification_2.md │
│ ✓ "Playback URL" → api-reference/get-playback-url.md │
│ ✓ "Python init" → api-reference/initialization_2.md │
│ ✓ "Auto transcode" → media-processing/workflow.md │
│ ✗ #1 Don't use root AK ✗ #3 Don't poll ✗ #5 URL encode ✗ #6 QPS backoff │
└────────────────────────┬─────────────────────────────────────┘
│
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
url-based-upload.md event-notification_2.md get-playback-url.md
- UploadMediaByURL - Event type list - Request/response params
- URL must be encoded - HTTP callback format - Definition enums
- Region limit - Timeout & retry policy - QPS=360/s
- Max 20 URLs - 5 sec timeout - Status=Normal
│ │ │
▼ ▼ ▼
└────► initialization_2.md (SDK client constructor) ◄────┘
│
▼
workflow.md (Auto-transcode with TemplateGroupId)
│
▼
Generate complete runnable codeKey design decisions
This table details the key design decisions for this demo and their basis in the documentation.
Decision point | Agent's choice | Basis in documentation |
Upload method | UploadMediaByURL | The documentation specifies this API for batch uploading from a list of public URLs. |
Transcoding trigger | Specify TemplateGroupId during upload | The documentation states that specifying |
Status tracking | HTTP event callback | Common Mistake #3: Do not poll. |
Timing for getting playback URL | After TranscodeComplete | The documentation states that |
AccessKey management | environment variables | Common Mistake #1: Do not hardcode. |
URL handling |
| Common Mistake #5: Must be encoded. |
Region | cn-shanghai | The documentation states that URL-based uploads are only supported in the China (Shanghai) region. |
Fault tolerance | Exponential backoff retry | Common Mistake #6: Backoff for throttling. |
Client-side demo: Android player and live viewer
This runnable Android demo builds on the server-side workflow. It shows how to play an MP4 file with minimal code and how to integrate an interactive live streaming viewer using AUI Kits.
Prompt submitted to the agent
Based on the client-side llms index (in directories like `client-side-player/`, `client-side-upload/`, `client-side-short-video/`), implement a demo app for Android.
Specific requirements:
1. Select the minimum required dependency package to play the playback URL returned by the server-side demo's GetPlayInfo response.
2. In the same app, add another entry point to enter an interactive live streaming viewer using AUI Kits (with stream pulling, bullet screen, likes, and gifts).
3. Make the package name, license, and AppServer domain configurable to avoid hardcoding.Agent execution process
Phase 1: Read the client-side llms index and match scenarios
Quick start matching results:
"Start VOD playback on Android" → client-side-player/player-atomic-android.md
"How to choose packages/dependencies" → client-side-player/player-overview.md
"How to integrate the license" → client-side-player/player-common-license.md
"Interactive live streaming viewer" → client-side-player/player-kits-aui.md
"Error codes 4400/4013" → client-side-player/player-common-error-codes.md
Common mistakes matched:
✗ Initializing the license after creating the player → Must be done in Application.onCreate
✗ Calling setSurface before the Surface is ready → Must wait for surfaceCreated
✗ Using the full-featured package by default → Choose the minimal package for the scenario
✗ Hardcoding the AppServer domain → Abstract to BuildConfig / gradle.properties
✗ Calling PrivateService.init multiple times → Initialize only once in the Application classPhase 2: Load detailed documentation on demand
Document | Purpose |
| Package selection decision (BasicLive / UGC / InteractiveLive / Standard) |
| Gradle dependencies, Manifest permissions, obfuscation, and minimal playback code |
| License integration timing and troubleshooting for errors 4400/4013 |
| AUI Kits client-side modules and AppServer collaboration model |
| Quick reference for playback start failures |
Phase 3: Extract key decisions
Package selection:
Playback only → AliVCSDK_BasicLive
Playback + short video → AliVCSDK_UGC
Includes co-hosting/interactive live streaming → AliVCSDK_InteractiveLive ← This demo chooses this one
Full-featured → AliVCSDK_Standard / Premium
License:
PrivateService.initService(ctx, licenseFile, licenseKey)
Must be completed before the first call to createAliPlayer
AUI Kits:
AppServer + client-side; AppServer issues Identity Token, Live Room Token, and IMS Token.
Client: Three modules - AUILiveRoomCore, AUILiveRoomViewer, and AUIInteraction.Execution results
Quick player integration
Project dependencies
In the project-level build.gradle file:
allprojects {
repositories {
google()
mavenCentral()
maven { url "https://maven.aliyun.com/nexus/content/repositories/releases" }
}
}In the app-level build.gradle file:
android {
compileSdk 34
defaultConfig {
applicationId "com.example.aliplayer.sample"
minSdk 21
targetSdk 34
ndk { abiFilters "armeabi-v7a", "arm64-v8a" }
buildConfigField "String", "APP_SERVER_HOST",
"\"${project.findProperty('APP_SERVER_HOST') ?: 'https://your-appserver.example.com'}\""
buildConfigField "String", "APP_SERVER_API_PREFIX", "\"/api/v1/live/\""
buildConfigField "String", "LICENSE_KEY",
"\"${project.findProperty('LICENSE_KEY') ?: ''}\""
}
buildFeatures { buildConfig true }
}
dependencies {
implementation 'com.aliyun.aio:AliVCSDK_InteractiveLive:6.0.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.11.0'
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
implementation 'com.google.code.gson:gson:2.10.1'
}Permissions and obfuscation
In the AndroidManifest.xml file:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />In the proguard-rules.pro file:
-keep class com.alivc.**{*;}
-keep class com.aliyun.**{*;}
-keep class com.cicada.**{*;}
-dontwarn com.alivc.**
-dontwarn com.aliyun.**
-dontwarn com.cicada.**License initialization
public class SampleApp extends Application {
@Override
public void onCreate() {
super.onCreate();
// Place license.crt in app/src/main/assets/
PrivateService.initService(getApplicationContext(),
"file:///android_asset/license.crt",
BuildConfig.LICENSE_KEY);
}
}Register it in the AndroidManifest.xml file:
<application
android:name=".SampleApp"
android:label="@string/app_name"
android:theme="@style/Theme.MaterialComponents.DayNight">
<activity android:name=".MainActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SimplePlayerActivity" />
</application>Single video playback UI
Generate the activity_player.xml file:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000">
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="220dp"
android:layout_gravity="center" />
</FrameLayout>Generate the SimplePlayerActivity.java file:
public class SimplePlayerActivity extends AppCompatActivity {
public static final String EXTRA_PLAY_URL = "play_url";
private AliPlayer aliPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player);
SurfaceView surfaceView = findViewById(R.id.surfaceView);
aliPlayer = AliPlayerFactory.createAliPlayer(getApplicationContext());
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override public void surfaceCreated(SurfaceHolder h) {
aliPlayer.setSurface(h.getSurface());
}
@Override public void surfaceChanged(SurfaceHolder h, int f, int w, int hh) {
aliPlayer.surfaceChanged();
}
@Override public void surfaceDestroyed(SurfaceHolder h) {
aliPlayer.setSurface(null);
}
});
aliPlayer.setOnPreparedListener(() -> aliPlayer.start());
aliPlayer.setOnErrorListener(err ->
Log.e("AliPlayer", "code=" + err.getCode() + " msg=" + err.getMsg()));
UrlSource source = new UrlSource();
// Source: The playback URL (with auth_key) from the server-side demo's GetPlayInfo response
String playUrl = getIntent().getStringExtra(EXTRA_PLAY_URL);
source.setUri(playUrl != null ? playUrl : "https://your.cdn/test.mp4");
aliPlayer.setDataSource(source);
aliPlayer.setAutoPlay(true);
aliPlayer.prepare();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (aliPlayer != null) {
aliPlayer.stop();
aliPlayer.release();
}
}
}If the prepared event and the first frame event appear in the logs and the SurfaceView renders the image correctly, it means the underlying link is clear.
AUI Kits live viewer
Import AUI Kits modules
In the settings.gradle file:
include ':app',
':AUILiveRoomCore',
':AUILiveRoomViewer',
':AUIInteraction'In the app-level build.gradle file:
implementation project(':AUILiveRoomCore')
implementation project(':AUILiveRoomViewer')
implementation project(':AUIInteraction')AppServer collaboration model
The client does not directly hold sensitive credentials like the IMS Token. Instead, the AppServer issues them after authentication. A complete workflow for entering a live room is as follows:
[Android App] [AppServer]
│ │
│── GET /api/v1/live/viewer/token?roomId=xxx ─►│
│ ├── Authenticates and issues:
│ │ userId / nick / pullUrl / imsToken
│◄──────── 200 OK + ViewerTokenInfo ───────────┤
│
│── LiveRoomViewerActivity.start(params) ──►(Inside AUI Kits)
│ │
│ (AliPlayer for stream pulling + IMS for bullet screen) │The Android app sends a
GET /api/v1/live/viewer/token?roomId=xxxrequest to the AppServer with the login state.The AppServer verifies the login status and issues the
userId,nick,pullUrl, andimsToken.After the app receives
ViewerTokenInfo, it callsLiveRoomViewerActivity.start(params)to enter the live room.Internally, AUI Kits uses AliPlayer for stream pulling and connects to the Interactive Messaging Service (IMS) for bullet screen, like, and gift features.
AppServerClient (OkHttp implementation)
public class AppServerClient {
public interface Callback {
void onSuccess(ViewerTokenInfo info);
void onFail(String msg);
}
private static final OkHttpClient client = new OkHttpClient();
public static void fetchViewerToken(String roomId, Callback cb) {
HttpUrl url = HttpUrl.parse(
BuildConfig.APP_SERVER_HOST + BuildConfig.APP_SERVER_API_PREFIX + "viewer/token")
.newBuilder()
.addQueryParameter("roomId", roomId)
.build();
Request req = new Request.Builder()
.url(url)
.header("Authorization", "Bearer " + LoginManager.getToken())
.build();
client.newCall(req).enqueue(new okhttp3.Callback() {
@Override public void onFailure(Call call, IOException e) {
cb.onFail(e.getMessage());
}
@Override public void onResponse(Call call, Response resp) throws IOException {
if (!resp.isSuccessful() || resp.body() == null) {
cb.onFail("HTTP " + resp.code());
return;
}
ViewerTokenInfo info = new Gson().fromJson(
resp.body().string(), ViewerTokenInfo.class);
cb.onSuccess(info);
}
});
}
}
public class ViewerTokenInfo {
public String roomId;
public String userId;
public String nick;
public String pullUrl; // Any of rtmp, flv, m3u8, or artc
public String imsToken; // Interactive Messaging Service (IMS) Token
}Combine the two demo entries
Generate the activity_main.xml file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="24dp"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button android:id="@+id/btnSimple"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Simple Playback" />
<Button android:id="@+id/btnLiveRoom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Interactive Live Viewer" />
</LinearLayout>Generate the MainActivity.java file:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btnSimple).setOnClickListener(v -> {
Intent intent = new Intent(this, SimplePlayerActivity.class);
// In a real application, pass the playback URL from the server-side demo's GetPlayInfo response here
intent.putExtra(SimplePlayerActivity.EXTRA_PLAY_URL,
"https://vod.example.com/****/sample1-hd.mp4?auth_key=****");
startActivity(intent);
});
findViewById(R.id.btnLiveRoom).setOnClickListener(v -> enterRoom("demo_room_001"));
}
private void enterRoom(String roomId) {
AppServerClient.fetchViewerToken(roomId, new AppServerClient.Callback() {
@Override public void onSuccess(ViewerTokenInfo info) {
LiveRoomEnterParams params = new LiveRoomEnterParams.Builder()
.roomId(info.roomId)
.userId(info.userId)
.userNick(info.nick)
.pullUrl(info.pullUrl)
.imsToken(info.imsToken)
.build();
LiveRoomViewerActivity.start(MainActivity.this, params);
}
@Override public void onFail(String msg) {
Toast.makeText(MainActivity.this, "Failed to enter room: " + msg, Toast.LENGTH_LONG).show();
}
});
}
}Verification checklist
After running the demo, verify the following UI behavior and log output:
Click Simple Playback: The
SimplePlayerActivitystarts, and the video plays smoothly in theSurfaceViewwithout a black screen.Click Interactive Live Streaming Viewer: The AUI Kits
LiveRoomViewerActivityis launched; AliPlayer displays the host's video feed; the bullet screen, like, and gift panels in the bottom right corner are functional.Key logcat logs: The simultaneous appearance of
AliPlayer: prepared,AliPlayer: first frame, andIMS: connectedindicates that both stream pulling and interaction are ready.
Agent document retrieval visualization
Prompt: "Android playback + enter interactive live room"
│
▼
┌── Client-side llms.txt (Quick start + Common mistakes) ────────┐
│ ✓ "Android playback" → player-atomic-android.md │
│ ✓ "How to choose package" → player-overview.md │
│ ✓ "License" → player-common-license.md │
│ ✓ "AUI Kits interactive" → player-kits-aui.md │
│ ✓ "Error codes 4400/4013" → player-common-error-codes.md │
│ ✗ License must be initialized before player creation │
│ ✗ Do not call setSurface before Surface is ready │
│ ✗ Do not use the full-featured package by default │
│ ✗ Do not hardcode the AppServer domain │
│ ✗ Call PrivateService.init only once in Application │
└────────────────────────┬────────────────────────────────────┘
│
┌─────────────┬────────┴─────────┬─────────────┐
▼ ▼ ▼ ▼
player- player-atomic- player-common- player-kits-aui.md
overview.md android.md license.md - AppServer collab
- Package matrix - gradle deps - PrivateService - Three token types
- Scenario map - Manifest perms - 4400/4013 - Module breakdown
- SDK size - Playback code - Package/BundleID - 4-step client integration
└─────────────┴────────┬─────────┴─────────────┘
│
▼
player-common-error-codes.md
(Guidance for 4400/4013/4034/4036)
│
▼
Generate complete runnable Android DemoKey design decisions
Decision point | Agent's choice | Basis in documentation |
SDK bundle | AliVCSDK_InteractiveLive | The selection matrix in |
License timing | Application.onCreate | player-common-license.md: Must be called before |
Surface binding |
|
|
AppServer domain | BuildConfig + gradle.properties | Common Mistake: Do not hardcode. |
Server-side integration | Reuse the playback URL from the server-side demo's GetPlayInfo response | This ensures end-to-end consistency between the server-side and client-side demos. |
Interactive live viewer | AUI Kits three modules (Core / Viewer / Interaction) | player-kits-aui.md: Main client-side integration guide. |
Error handling |
|
|
Pre-launch checklist (Android)
Dimension | Check item |
License | Test and production licenses have been applied for and configured in their respective BuildConfigs. |
Package size |
|
Playback start | Listeners for 4400/4013/4034/4036 are implemented for monitoring. |
Live room | Automatic renewal for expired IMS Tokens is implemented; AppServer has HTTPS and CORS enabled. |
Privacy | Permissions for audio recording, network access, and media reading are all declared in the privacy policy. |
Canary release | First, release the new version to 5% of users. Monitor the first-frame time and failure rates for 48 hours before a full rollout. |
Monitoring | Enable Alibaba Cloud's player quality monitoring service (QoS) and single-point tracing. |
Final directory structure
AliPlayerSampleApp/
├── app/
│ ├── src/main/
│ │ ├── assets/license.crt
│ │ ├── java/com/example/aliplayer/sample/
│ │ │ ├── SampleApp.java
│ │ │ ├── MainActivity.java
│ │ │ ├── SimplePlayerActivity.java ← Simple Playback
│ │ │ ├── AppServerClient.java ← Interactive Live Streaming
│ │ │ ├── ViewerTokenInfo.java
│ │ │ └── LoginManager.java
│ │ └── AndroidManifest.xml
│ └── build.gradle
├── AUILiveRoomCore/ ← Interactive Live Streaming
├── AUILiveRoomViewer/ ← Interactive Live Streaming
├── AUIInteraction/ ← Interactive Live Streaming
├── gradle.properties (APP_SERVER_HOST / LICENSE_KEY)
├── settings.gradle
└── build.gradleThe server-side and client-side demos now form a complete, closed-loop workflow. This workflow, generated by the Agent using the llms.txt index, covers video uploading, automatic transcoding, playback URL retrieval, basic video playback, and an interactive live streaming viewer using AUI Kits.
Appendix: Agent selection and self-check
This appendix is for developers who have not used or installed a Coding Agent.
When to use a Coding Agent
Use case | Is it needed? |
You want the AI to read | Yes |
You only want to read this document to understand the architecture, then copy and manually modify the code. | No. A web browser is sufficient. |
You want the AI to directly add, delete, and modify files in your local repository and run commands to validate the changes. | Yes |
Recommended options
Category | Name | Type | Description |
Recommended | Qoder / Cursor / Claude Code | Desktop IDE or CLI | Natively supports long-document retrieval using |
Other | - | - | Any Coding Agent that can access URLs, write local files, and call shell commands. |
Use the installation links from the official product website. Avoid using third-party images.
Minimum self-check
Send the following prompt to your Coding Agent to verify its capabilities:
Please read https://ice-document-materials.oss-cn-shanghai.aliyuncs.com/vod/llms/llms.txt,
and tell me:
1. How many top-level modules are in this index? What are they?
2. Which sub-documents are involved in the "batch upload + automatic transcoding + get audio/video playback URL" workflow? Please list their relative paths.
3. In the "Common mistakes to avoid" section, what are the notes related to "AccessKey"?Expected Answers:
Correctly lists the top-level modules from
llms.txt.Provides a list of sub-documents that is largely consistent with the on-demand loading table in the server-side demo (media upload, event notification, get audio/video playback URL, Python SDK initialization, media processing workflow).
Clearly states: Do not use an Alibaba Cloud account AccessKey. Use a RAM user instead.
An agent that passes all three checks is ready for the demos in this document.