or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

bucket.mdclient.mdcluster.mdimage.mdindex.mdmultipart.mdobject.mdrtmp.mdsts.md
tile.json

rtmp.mddocs/

Live Streaming (RTMP)

The RTMP Live Streaming service provides capabilities for creating and managing live streaming channels, controlling streaming status, and generating Video-on-Demand (VOD) content from live streams.

Channel Management

Create Live Channel

async function putChannel(id: string, conf: ChannelConfig, options?: RequestOptions): Promise<PutChannelResult>;

interface ChannelConfig {
  name: string;
  description?: string;
  status?: 'enabled' | 'disabled';
  type?: 'HLS';
  fragDuration?: number;
  fragCount?: number;
  playlistName?: string;
}

interface PutChannelResult {
  publishUrls: string[];
  playUrls: string[];
  res: ResponseInfo;
}

Get Channel Information

async function getChannel(id: string, options?: RequestOptions): Promise<GetChannelResult>;

interface GetChannelResult {
  name: string;
  description?: string;
  status: 'enabled' | 'disabled';
  type: string;
  fragDuration: number;
  fragCount: number;
  playlistName: string;
  createTime: Date;
  lastModified: Date;
  res: ResponseInfo;
}

Delete Live Channel

async function deleteChannel(id: string, options?: RequestOptions): Promise<DeleteChannelResult>;

interface DeleteChannelResult {
  res: ResponseInfo;
}

List Live Channels

async function listChannels(query?: ListChannelsQuery, options?: RequestOptions): Promise<ListChannelsResult>;

interface ListChannelsQuery {
  prefix?: string;
  marker?: string;
  'max-keys'?: number;
}

interface ListChannelsResult {
  channels: ChannelInfo[];
  isTruncated: boolean;
  nextMarker?: string;
  res: ResponseInfo;
}

interface ChannelInfo {
  name: string;
  description?: string;
  status: 'enabled' | 'disabled';
  lastModified: Date;
  publishUrls: string[];
  playUrls: string[];
}

Channel Control

Set Channel Status

async function putChannelStatus(id: string, status: 'enabled' | 'disabled', options?: RequestOptions): Promise<PutChannelStatusResult>;

interface PutChannelStatusResult {
  res: ResponseInfo;
}

Get Channel Status

async function getChannelStatus(id: string, options?: RequestOptions): Promise<GetChannelStatusResult>;

interface GetChannelStatusResult {
  status: 'Live' | 'Idle';
  connectedTime?: Date;
  remoteAddr?: string;
  video?: VideoInfo;
  audio?: AudioInfo;
  res: ResponseInfo;
}

interface VideoInfo {
  width: number;
  height: number;
  frameRate: number;
  bandwidth: number;
  codec: string;
}

interface AudioInfo {
  bandwidth: number;
  sampleRate: number;
  codec: string;
}

Get Channel History

async function getChannelHistory(id: string, options?: RequestOptions): Promise<GetChannelHistoryResult>;

interface GetChannelHistoryResult {
  records: StreamRecord[];
  res: ResponseInfo;
}

interface StreamRecord {
  startTime: Date;
  endTime: Date;
  remoteAddr: string;
}

VOD Operations

Create VOD Playlist

async function createVod(id: string, name: string, time: VodTime, options?: RequestOptions): Promise<CreateVodResult>;

interface VodTime {
  startTime: number; // Unix timestamp in seconds (epoch time)
  endTime: number;   // Unix timestamp in seconds (epoch time)
}

interface CreateVodResult {
  res: ResponseInfo;
}

URL Generation

Get RTMP URL

function getRtmpUrl(channelId: string, options?: RtmpUrlOptions): string;

interface RtmpUrlOptions {
  expires?: number; // URL expiration time in seconds
  params?: Record<string, string>; // Additional URL parameters for authentication or configuration
}

Usage Examples

Basic Live Streaming Setup

const OSS = require('ali-oss');

const client = new OSS({
  region: 'oss-cn-hangzhou',
  accessKeyId: 'your-access-key-id',
  accessKeySecret: 'your-access-key-secret',
  bucket: 'your-live-bucket'
});

// Create a live channel
const channelResult = await client.putChannel('live-channel-1', {
  name: 'My Live Stream',
  description: 'Live streaming channel for events',
  status: 'enabled',
  type: 'HLS',
  fragDuration: 5,     // 5 second fragments
  fragCount: 3,        // Keep 3 fragments in playlist
  playlistName: 'playlist.m3u8'
});

console.log('Publish URLs:', channelResult.publishUrls);
console.log('Play URLs:', channelResult.playUrls);

Channel Management

// List all channels
const channels = await client.listChannels({
  prefix: 'live-',
  'max-keys': 10
});

console.log('Active channels:', channels.channels.length);

// Get specific channel info
const channelInfo = await client.getChannel('live-channel-1');
console.log('Channel status:', channelInfo.status);
console.log('Created:', channelInfo.createTime);

// Check if channel is currently streaming
const status = await client.getChannelStatus('live-channel-1');
if (status.status === 'Live') {
  console.log('Stream is live!');
  console.log('Connected from:', status.remoteAddr);
  console.log('Video:', `${status.video.width}x${status.video.height} @ ${status.video.frameRate}fps`);
} else {
  console.log('Channel is idle');
}

Channel Control

// Enable/disable channel
await client.putChannelStatus('live-channel-1', 'enabled');
console.log('Channel enabled');

// Disable channel (stops any active streams)
await client.putChannelStatus('live-channel-1', 'disabled');
console.log('Channel disabled');

// Get streaming history
const history = await client.getChannelHistory('live-channel-1');
console.log('Stream sessions:', history.records.length);
history.records.forEach(record => {
  console.log(`Session: ${record.startTime} - ${record.endTime} from ${record.remoteAddr}`);
});

VOD Creation

// Create VOD from live stream segment
await client.createVod('live-channel-1', 'highlight-clip', {
  startTime: Math.floor(Date.now() / 1000) - 3600, // 1 hour ago
  endTime: Math.floor(Date.now() / 1000) - 3000    // 50 minutes ago
});

console.log('VOD playlist created');

URL Generation with Authentication

// Generate RTMP publish URL with expiration
const publishUrl = client.getRtmpUrl('live-channel-1', {
  expires: 3600, // 1 hour
  params: {
    'stream-key': 'secure-stream-key-123'
  }
});

console.log('Publish URL:', publishUrl);
// Use this URL in streaming software like OBS

Advanced Configuration

High-Quality Streaming Configuration

// Create channel optimized for high-quality streaming
const hqChannel = await client.putChannel('hq-stream', {
  name: 'High Quality Stream',
  description: 'HD streaming channel',
  status: 'enabled',
  type: 'HLS',
  fragDuration: 2,     // Shorter fragments for lower latency
  fragCount: 5,        // More fragments for better buffering
  playlistName: 'hq-playlist.m3u8'
});

Multiple Channel Management

// Create multiple channels for different purposes
const channels = [
  { id: 'main-stage', name: 'Main Stage', description: 'Primary event stream' },
  { id: 'backstage', name: 'Backstage', description: 'Behind the scenes' },
  { id: 'audience', name: 'Audience View', description: 'Audience perspective' }
];

for (const channel of channels) {
  const result = await client.putChannel(channel.id, {
    name: channel.name,
    description: channel.description,
    status: 'enabled',
    type: 'HLS',
    fragDuration: 3,
    fragCount: 4
  });
  
  console.log(`Channel ${channel.id} created`);
  console.log(`Publish: ${result.publishUrls[0]}`);
  console.log(`Play: ${result.playUrls[0]}`);
}

Monitoring and Analytics

Stream Monitoring

async function monitorChannels(channelIds) {
  const report = {
    live: [],
    idle: [],
    total: channelIds.length
  };
  
  for (const channelId of channelIds) {
    try {
      const status = await client.getChannelStatus(channelId);
      
      if (status.status === 'Live') {
        report.live.push({
          id: channelId,
          connectedTime: status.connectedTime,
          remoteAddr: status.remoteAddr,
          video: status.video,
          audio: status.audio
        });
      } else {
        report.idle.push(channelId);
      }
    } catch (error) {
      console.error(`Failed to check status for ${channelId}:`, error);
    }
  }
  
  return report;
}

// Monitor channels every 30 seconds
setInterval(async () => {
  const report = await monitorChannels(['main-stage', 'backstage', 'audience']);
  console.log(`Live channels: ${report.live.length}/${report.total}`);
}, 30000);

Stream History Analysis

async function analyzeStreamHistory(channelId, days = 7) {
  const history = await client.getChannelHistory(channelId);
  
  const cutoffDate = new Date();
  cutoffDate.setDate(cutoffDate.getDate() - days);
  
  const recentSessions = history.records.filter(
    record => record.startTime >= cutoffDate
  );
  
  const totalDuration = recentSessions.reduce((total, record) => {
    return total + (record.endTime.getTime() - record.startTime.getTime());
  }, 0);
  
  return {
    sessionCount: recentSessions.length,
    totalDurationHours: totalDuration / (1000 * 60 * 60),
    averageDurationMinutes: (totalDuration / recentSessions.length) / (1000 * 60),
    uniqueIPs: [...new Set(recentSessions.map(r => r.remoteAddr))].length
  };
}

Error Handling

Channel Operation Errors

try {
  await client.putChannel('new-channel', channelConfig);
} catch (error) {
  if (error.code === 'ChannelAlreadyExists') {
    console.log('Channel already exists, updating configuration...');
    // Update existing channel or use different name
  } else if (error.code === 'InvalidChannelName') {
    console.error('Invalid channel name format');
  } else {
    console.error('Channel creation failed:', error.message);
  }
}

Streaming Status Errors

try {
  const status = await client.getChannelStatus('live-channel');
  
  if (status.status === 'Live') {
    // Handle active stream
  } else {
    // Handle idle channel
  }
} catch (error) {
  if (error.code === 'NoSuchLiveChannel') {
    console.error('Channel does not exist');
  } else if (error.code === 'ChannelNotLive') {
    console.log('Channel is not currently streaming');
  } else {
    console.error('Status check failed:', error.message);
  }
}

Best Practices

Channel Configuration

  • Use shorter fragment durations (2-3 seconds) for low-latency applications
  • Use longer fragment durations (5-10 seconds) for better bandwidth efficiency
  • Keep 3-5 fragments in playlist for optimal buffering
  • Use descriptive channel names and descriptions for management

Security

// Use time-limited publish URLs
const securePublishUrl = client.getRtmpUrl('secure-channel', {
  expires: 1800, // 30 minutes
  params: {
    'auth-token': generateSecureToken(),
    'user-id': userId
  }
});

Performance Optimization

  • Monitor channel status regularly but not too frequently (every 30-60 seconds)
  • Clean up old channels that are no longer needed
  • Use appropriate fragment settings based on use case
  • Implement proper error handling and retry logic

VOD Management

// Create VOD highlights after stream ends
async function createHighlights(channelId, streamStartTime, streamEndTime) {
  const highlights = [
    { name: 'opening', start: streamStartTime, duration: 300 },      // First 5 minutes
    { name: 'peak', start: streamStartTime + 1800, duration: 600 },  // 30min mark, 10min clip
    { name: 'closing', start: streamEndTime - 300, duration: 300 }   // Last 5 minutes
  ];
  
  for (const highlight of highlights) {
    await client.createVod(channelId, highlight.name, {
      startTime: highlight.start,
      endTime: highlight.start + highlight.duration
    });
    
    console.log(`Created ${highlight.name} highlight`);
  }
}