すべてのプロダクト
Search
ドキュメントセンター

ApsaraVideo Live:汎用モードのプロダクションスタジオの API 呼び出しデモ

最終更新日:Nov 09, 2025

このトピックでは、汎用モードのプロダクションスタジオの OpenAPI を呼び出して基本操作を実行する方法を示すサンプルコードを提供します。

プロダクションスタジオのライフサイクル

汎用モードのプロダクションスタジオのライフサイクルは、次のステップで構成されます。

重要

レイアウトを追加する前に、ビデオソースを追加する必要があります。そうしないと、レイアウトは適用されません。

  1. プロダクションスタジオを作成する

  2. プロダクションスタジオを設定する

  3. ビデオソースを追加する

  4. レイアウトを追加する

  5. 再生シーンを設定する

  6. (オプション) コンポーネントを追加する

    リアルタイム字幕、イメージ、テキストなどのコンポーネントは、要件に基づいて作成できます。

  7. プロダクションスタジオを開始する

  8. プロダクションスタジオを停止する

  9. プロダクションスタジオを削除する

サンプルコード

説明
  • プロダクションスタジオの作成

    // プロダクションスタジオを作成します。
    func CreateCaster(liveClient *live20161101.Client) (*live20161101.CreateCasterResponse, error) {
    	// プロダクションスタジオを作成するためのリクエストパラメーター。
    	createCasterRequest := &live20161101.CreateCasterRequest{}
    	createCasterRequest.ClientToken = tea.String(uuid.New().String())
    	createCasterRequest.CasterName = tea.String("Production studio for testing")
    	createCasterRequest.ChargeType = tea.String("PostPaid")
    	createCasterRequest.NormType = tea.Int32(1)
    	createCasterResponse, err := liveClient.CreateCaster(createCasterRequest)
    	if err != nil {
    		return nil, errors.New("CreateCaster failed: " + err.Error())
    	}
    	return createCasterResponse, nil
    }

    CreateCaster 操作のリクエストパラメーターの詳細については、「CreateCaster」をご参照ください。

  • プロダクションスタジオの設定

    // プロダクションスタジオを設定します。
    func SetCasterConfig(liveClient *live20161101.Client, casterId *string, domainName *string) (*live20161101.SetCasterConfigResponse, error) {
    	// プロダクションスタジオを設定するためのパラメーター。
    	createSetCasterConfig := &live20161101.SetCasterConfigRequest{}
    	createSetCasterConfig.CasterId = casterId
    	createSetCasterConfig.CasterName = tea.String("Production studio for testing")
    	createSetCasterConfig.ChannelEnable = tea.Int32(1)
    	createSetCasterConfig.Delay = tea.Float32(0)
    	createSetCasterConfig.DomainName = domainName
    	createSetCasterConfig.ProgramEffect = tea.Int32(1)
    	createSetCasterConfig.ProgramName = tea.String("test loop play")
    	// トランスコーディング設定 (画面の向きと解像度)。
    	// CasterTemplate パラメーターは、次の値に設定できます: lp_ld (低解像度)、lp_sd (標準解像度)、lp_hd (高解像度)、または lp_ud (超高解像度)。lp_ld_v (縦モードの低解像度)、lp_sd_v (縦モードの標準解像度)、lp_hd_v (縦モードの高解像度)、または lp_ud_v (縦モードの超高解像度)。
    	createSetCasterConfig.TranscodeConfig = tea.String(`{"CasterTemplate": "lp_ld"}`)
    	// プロダクションスタジオの録画パラメーターを設定します。JSON フィールドの詳細については、AddLiveAppRecordConfig をご参照ください。
    	// createSetCasterConfig.RecordConfig = tea.String(`{ "endpoint": "", "ossBucket": "", "videoFormat": [{"format": "flv", "interval": 900, "prefix":"record/{AppName}/{StreamName}/{StartTime}_{EndTime}" }]}`)
    	setCasterConfigResponse, err := liveClient.SetCasterConfig(createSetCasterConfig)
    	if err != nil {
    		return nil, errors.New("SetCasterConfig failed: " + err.Error())
    	}
    	return setCasterConfigResponse, nil
    }

    SetCasterConfig 操作の詳細については、「SetCasterConfig」をご参照ください。

  • ビデオソースを追加してチャンネルにバインドする

    // ビデオソースを追加します。
    func AddCasterVideoResource(liveClient *live20161101.Client, casterId *string) error {
    	// プロダクションスタジオのビデオソースを作成します。
    	addCasterVideoResourceRequest := &live20161101.AddCasterVideoResourceRequest{}
    	addCasterVideoResourceRequest.CasterId = casterId
    	addCasterVideoResourceRequest.ResourceName = tea.String("Video source for testing")
    	addCasterVideoResourceRequest.LiveStreamUrl = tea.String("xxxxx")
    	addCasterVideoResourceRequest.PtsCallbackInterval = tea.Int32(1000)
    	addCasterVideoResourceResp, err := liveClient.AddCasterVideoResource(addCasterVideoResourceRequest)
    	if err != nil {
    		return errors.New("AddCasterVideoResource failed: " + err.Error())
    	}
    	resourceId := addCasterVideoResourceResp.Body.ResourceId
    
    	// ビデオソースをチャンネルにバインドします。
    	setCasterChannelRequest := &live20161101.SetCasterChannelRequest{}
    	setCasterChannelRequest.CasterId = casterId
    	setCasterChannelRequest.PlayStatus = tea.Int32(1)
    	setCasterChannelRequest.ChannelId = tea.String("RV01")
    	setCasterChannelRequest.ResourceId = resourceId
    	_, err = liveClient.SetCasterChannel(setCasterChannelRequest)
    	if err != nil {
    		return errors.New("SetCasterChannel failed: " + err.Error())
    	}
    	return nil
    }

    AddCasterVideoResource 操作の詳細については、「AddCasterVideoResource」をご参照ください。

  • レイアウトの追加

    // レイアウトを追加します。
    func AddCasterLayout(liveClient *live20161101.Client, casterId *string) (*live20161101.AddCasterLayoutResponse, error) {
    	// レイアウトを作成します。
    	addCasterLayoutRequest := &live20161101.AddCasterLayoutRequest{}
    	addCasterLayoutRequest.CasterId = casterId
    	addCasterLayoutRequest.BlendList = []*string{tea.String("RV01")} // ビデオの位置。
    	addCasterLayoutRequest.MixList = []*string{tea.String("RV01")}   // ビデオの位置。
    
    	audioLayer := &live20161101.AddCasterLayoutRequestAudioLayer{}
    	audioLayer.VolumeRate = tea.Float32(1)
    	audioLayer.ValidChannel = tea.String("all")
    	audioLayer.FixedDelayDuration = tea.Int32(0)
    
    	addCasterLayoutRequest.AudioLayer = []*live20161101.AddCasterLayoutRequestAudioLayer{
    		audioLayer,
    	}
    
    	videoLayer := &live20161101.AddCasterLayoutRequestVideoLayer{
    		FillMode:           tea.String("fit"),
    		HeightNormalized:   tea.Float32(1),
    		WidthNormalized:    tea.Float32(1),
    		PositionRefer:      tea.String("topLeft"),
    		PositionNormalized: []*float32{tea.Float32(0), tea.Float32(0)},
    		FixedDelayDuration: tea.Int32(0),
    	}
    
    	addCasterLayoutRequest.VideoLayer = []*live20161101.AddCasterLayoutRequestVideoLayer{
    		videoLayer,
    	}
    	addCasterLayoutResponse, err := liveClient.AddCasterLayout(addCasterLayoutRequest)
    	if err != nil {
    		return nil, errors.New("AddCasterLayout failed: " + err.Error())
    	}
    	return addCasterLayoutResponse, nil
    }

    詳細については、「AddCasterLayout」をご参照ください。

  • プロダクションスタジオを開始して再生シーンを設定する

    // プロダクションスタジオを開始して再生シーンを設定します。
    func StartCaster(liveClient *live20161101.Client, casterId *string, layoutId *string) (*live20161101.StartCasterResponse, error) {
    	// プロダクションスタジオを開始します。
    	startCasterRequest := &live20161101.StartCasterRequest{
    		CasterId: casterId,
    	}
    	startCasterResp, err := liveClient.StartCaster(startCasterRequest)
    	if err != nil {
    		return nil, errors.New("StartCaster failed: " + err.Error())
    	}
    
    	// リソースの読み込みには時間がかかります。プロダクションスタジオをすぐに開始すると、リソースの読み込みに失敗する可能性があります。そのため、しばらくプロセスを一時停止する必要があります。
    	time.Sleep(time.Second)
    
    	// 再生シーンを設定します。
    	// PVW (オプション)
    	setCasterSceneConfigRequest := &live20161101.SetCasterSceneConfigRequest{
    		CasterId: casterId,
    		LayoutId: layoutId,
    		SceneId:  startCasterResp.Body.PvwSceneInfos.SceneInfo[0].SceneId,
    	}
    
    	_, err = liveClient.SetCasterSceneConfig(setCasterSceneConfigRequest)
    	if err != nil {
    		return nil, errors.New("SetCasterSceneConfig failed: " + err.Error())
    	}
    	// PGM (必須)
    	setCasterSceneConfigRequest.SceneId = startCasterResp.Body.PgmSceneInfos.SceneInfo[0].SceneId
    	_, err = liveClient.SetCasterSceneConfig(setCasterSceneConfigRequest)
    	if err != nil {
    		return nil, errors.New("SetCasterSceneConfig failed: " + err.Error())
    	}
    	return startCasterResp, nil
    }

    StartCaster 操作の詳細については、「StartCaster」をご参照ください。

    SetCasterSceneConfig 操作の詳細については、「SetCasterSceneConfig」をご参照ください。

  • リアルタイム字幕コンポーネントを追加してシーンに適用する

    // リアルタイム字幕コンポーネントを追加してシーンに適用します。
    func AddETComponent(liveClient *live20161101.Client, casterId *string, layoutId *string, pgmSceneId *string) error {
    	// 前提条件: プロダクションスタジオが作成され、ライブストリームがビデオソースとして追加され、locationID が RV01 であること。
    	// 注: リアルタイム字幕はライブストリームでのみ有効です。
    	// コンポーネントを作成します。
    	r := &live20161101.AddCasterComponentRequest{
    		CasterId:       casterId,
    		ComponentType:  tea.String("caption"),
    		ComponentName:  tea.String("Real-time subtitles for testing"),
    		Effect:         tea.String("none"),
    		LocationId:     tea.String("RV01"),
    		ComponentLayer: tea.String(`{"HeightNormalized":"1","WidthNormalized":"1","PositionRefer":"topLeft","PositionNormalized":["0.05", "0.7"]}`),
    		// 字幕フィールドの詳細については、AddCasterComponent トピックの CaptionLayerContent パラメーターの説明をご参照ください。
    		// 次のフィールドが追加されます。公式ドキュメントは更新されていないことにご注意ください。
    		// BoxWidthNormalized: テキストのバックグラウンドの正規化された幅。この値はフォントサイズに基づいて計算されます (boxWidth/font_size)。計算値が 16 を超える場合は、値 16 が使用されます。デフォルト値: 0。
    		// BoxColor: テキストのバックグラウンドの色。値は 0xRGBA フォーマットです。たとえば、0xff0000ff は不透明な赤を示します。デフォルト値は "" で、このパラメーターが無効であることを示します。
    		// ShadowxWidthNormalized: テキストの網掛けの x 座標の正規化された値。この値はフォントサイズに基づいて計算されます (shadowxWidth/font_size)。計算値が 16 を超える場合は、値 16 が使用されます。デフォルト値: 0。
    		// ShadowyWidthNormalized: テキストの網掛けの y 座標の正規化された値。この値はフォントサイズに基づいて計算されます (shadowyWidth/font_size)。計算値が 16 を超える場合は、値 16 が使用されます。デフォルト値: 0。
    		// ShadowColor: テキストの網掛けの色。値は 0xRGBA フォーマットです。たとえば、0xff0000ff は不透明な赤を示します。デフォルト値は "" で、このパラメーターが無効であることを示します。
    		CaptionLayerContent: tea.String(`{
            "SizeNormalized": 0.05,
            "Color": "0xFFFFFF",
            "LocationId": "RV01",
            "BorderColor": "0x696969",
            "BorderWidthNormalized": 0.1,
            "BoxColor": "0xffffff",
            "BoxWidthNormalized": 0.7,
            "ShadowColor": "0x3c3c3c",
            "ShadowxWidthNormalized": 0.4,
            "ShadowyWidthNormalized": 0.4,
            "SourceLan": "cn",
            "TargetLan": "en",
            "PtsOffset": -1000,
            "SourceLanPerLineWordCount": 28,
            "TargetLanPerLineWordCount": 60,
            "ShowSourceLan": true,
            "ShowTargetLan": true,
            "Truncation": false,
            "AppearDuration": 20000,
            "AppearMode": "Movie"
            }`),
    	}
    
    	addCasterComponentResp, err := liveClient.AddCasterComponent(r)
    	if err != nil {
    		return errors.New("AddCasterComponent failed: " + err.Error())
    	}
    
    	// 指定したシーンにコンポーネントを適用します。
    	setCasterSceneConfigRequest := &live20161101.UpdateCasterSceneConfigRequest{
    		CasterId:    casterId,
    		LayoutId:    layoutId,
    		SceneId:     pgmSceneId,
    		ComponentId: []*string{addCasterComponentResp.Body.ComponentId},
    	}
    
    	_, err = liveClient.UpdateCasterSceneConfig(setCasterSceneConfigRequest)
    	if err != nil {
    		return errors.New("UpdateCasterSceneConfig failed: " + err.Error())
    	}
    	return nil
    }

    AddCasterComponent 操作の詳細については、「AddCasterComponent」をご参照ください。

    SetCasterSceneConfig 操作の詳細については、「SetCasterSceneConfig」をご参照ください。

  • レイアウトの切り替え

    // レイアウトを切り替えます。
    func ChangeLayout(liveClient *live20161101.Client, casterId *string, pgmSceneId *string, newLayoutId *string) error {
    	// シーンのレイアウト ID を変更します。
    	setCasterSceneConfigRequest := &live20161101.UpdateCasterSceneConfigRequest{
    		CasterId: casterId,
    		SceneId:  pgmSceneId,
    		LayoutId: newLayoutId,
    	}
    	_, err := liveClient.UpdateCasterSceneConfig(setCasterSceneConfigRequest)
    	if err != nil {
    		return errors.New("UpdateCasterSceneConfig failed: " + err.Error())
    	}
    	return nil
    }

    SetCasterSceneConfig 操作の詳細については、「SetCasterSceneConfig」をご参照ください。

  • プロダクションスタジオの停止

    // プロダクションスタジオを停止します。
    func StopCaster(liveClient *live20161101.Client, casterId *string) error {
    	stopCasterRequest := &live20161101.StopCasterRequest{
    		CasterId: casterId,
    	}
    	_, err := liveClient.StopCaster(stopCasterRequest)
    	if err != nil {
    		return errors.New("StopCaster failed: " + err.Error())
    	}
    	return nil
    }

    StopCaster 操作の詳細については、「StopCaster」をご参照ください。

  • プロダクションスタジオの削除

    // プロダクションスタジオを削除します。
    func DeleteCaster(liveClient *live20161101.Client, casterId *string) error {
    	deleteCasterRequest := &live20161101.DeleteCasterRequest{
    		CasterId: casterId,
    	}
    	_, err := liveClient.DeleteCaster(deleteCasterRequest)
    	if err != nil {
    		return errors.New("DeleteCaster failed: " + err.Error())
    	}
    	return nil
    }

    DeleteCaster 操作の詳細については、「DeleteCaster」をご参照ください。

package main

import (
	"errors"
	"log"
	"sync"
	"time"

	openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
	live20161101 "github.com/alibabacloud-go/live-20161101/v2/client"
	"github.com/alibabacloud-go/tea/tea"
	"github.com/google/uuid"
	"gopkg.in/ini.v1"
)

type LiveClient struct {
	instance *live20161101.Client
	once     sync.Once
}

var liveClientInstance = &LiveClient{}

func GetClientInstance() (*live20161101.Client, error) {
	section, err := getAccessKey()
	if err != nil {
		return nil, err
	}
	liveClientInstance.once.Do(func() {
		cfg := &openapi.Config{
			Endpoint:        tea.String("live.aliyuncs.com"),
			AccessKeyId:     tea.String(section.Key("access_key_id").String()),
			AccessKeySecret: tea.String(section.Key("access_key_secret").String()),
		}

		liveClientInstance.instance, err = live20161101.NewClient(cfg)
		if err != nil {
			err = errors.New("Live client initialization failed: " + err.Error())
		}
	})
	if err != nil {
		return nil, err
	}
	return liveClientInstance.instance, nil
}

func getAccessKey() (*ini.Section, error) {
	cfg, err := ini.Load("conf/config.ini")
	if err != nil {
		return nil, errors.New("ERROR: Can not open file " + err.Error())
	}
	section, err := cfg.GetSection("")
	if err != nil {
		return nil, errors.New("ERROR: Can not find section " + err.Error())
	}
	return section, nil
}

// プロダクションスタジオを作成します。
func CreateCaster(liveClient *live20161101.Client) (*live20161101.CreateCasterResponse, error) {
	// プロダクションスタジオを作成するためのリクエストパラメーター。
	createCasterRequest := &live20161101.CreateCasterRequest{}
	createCasterRequest.ClientToken = tea.String(uuid.New().String())
	createCasterRequest.CasterName = tea.String("Production studio for testing")
	createCasterRequest.ChargeType = tea.String("PostPaid")
	createCasterRequest.NormType = tea.Int32(1)
	createCasterResponse, err := liveClient.CreateCaster(createCasterRequest)
	if err != nil {
		return nil, errors.New("CreateCaster failed: " + err.Error())
	}
	return createCasterResponse, nil
}

// プロダクションスタジオを設定します。
func SetCasterConfig(liveClient *live20161101.Client, casterId *string, domainName *string) (*live20161101.SetCasterConfigResponse, error) {
	// プロダクションスタジオを設定するためのパラメーター。
	createSetCasterConfig := &live20161101.SetCasterConfigRequest{}
	createSetCasterConfig.CasterId = casterId
	createSetCasterConfig.CasterName = tea.String("Production studio for testing")
	createSetCasterConfig.ChannelEnable = tea.Int32(1)
	createSetCasterConfig.Delay = tea.Float32(0)
	createSetCasterConfig.DomainName = domainName
	createSetCasterConfig.ProgramEffect = tea.Int32(1)
	createSetCasterConfig.ProgramName = tea.String("test loop play")
	// トランスコーディング設定 (画面の向きと解像度)。
	// CasterTemplate パラメーターは、次の値に設定できます: lp_ld (低解像度)、lp_sd (標準解像度)、lp_hd (高解像度)、または lp_ud (超高解像度)。lp_ld_v (縦モードの低解像度)、lp_sd_v (縦モードの標準解像度)、lp_hd_v (縦モードの高解像度)、または lp_ud_v (縦モードの超高解像度)。
	createSetCasterConfig.TranscodeConfig = tea.String(`{"CasterTemplate": "lp_ld"}`)
	// プロダクションスタジオの録画パラメーターを設定します。JSON フィールドの詳細については、AddLiveAppRecordConfig をご参照ください。
	// createSetCasterConfig.RecordConfig = tea.String(`{ "endpoint": "", "ossBucket": "", "videoFormat": [{"format": "flv", "interval": 900, "prefix":"record/{AppName}/{StreamName}/{StartTime}_{EndTime}" }]}`)
	setCasterConfigResponse, err := liveClient.SetCasterConfig(createSetCasterConfig)
	if err != nil {
		return nil, errors.New("SetCasterConfig failed: " + err.Error())
	}
	return setCasterConfigResponse, nil
}

// ビデオソースを追加します。
func AddCasterVideoResource(liveClient *live20161101.Client, casterId *string) error {
	// プロダクションスタジオのビデオソースを作成します。
	addCasterVideoResourceRequest := &live20161101.AddCasterVideoResourceRequest{}
	addCasterVideoResourceRequest.CasterId = casterId
	addCasterVideoResourceRequest.ResourceName = tea.String("Video source for testing")
	addCasterVideoResourceRequest.LiveStreamUrl = tea.String("xxxxx")
	addCasterVideoResourceRequest.PtsCallbackInterval = tea.Int32(1000)
	addCasterVideoResourceResp, err := liveClient.AddCasterVideoResource(addCasterVideoResourceRequest)
	if err != nil {
		return errors.New("AddCasterVideoResource failed: " + err.Error())
	}
	resourceId := addCasterVideoResourceResp.Body.ResourceId

	// ビデオソースをチャンネルにバインドします。
	setCasterChannelRequest := &live20161101.SetCasterChannelRequest{}
	setCasterChannelRequest.CasterId = casterId
	setCasterChannelRequest.PlayStatus = tea.Int32(1)
	setCasterChannelRequest.ChannelId = tea.String("RV01")
	setCasterChannelRequest.ResourceId = resourceId
	_, err = liveClient.SetCasterChannel(setCasterChannelRequest)
	if err != nil {
		return errors.New("SetCasterChannel failed: " + err.Error())
	}
	return nil
}

// レイアウトを追加します。
func AddCasterLayout(liveClient *live20161101.Client, casterId *string) (*live20161101.AddCasterLayoutResponse, error) {
	// レイアウトを作成します。
	addCasterLayoutRequest := &live20161101.AddCasterLayoutRequest{}
	addCasterLayoutRequest.CasterId = casterId
	addCasterLayoutRequest.BlendList = []*string{tea.String("RV01")} // ビデオの位置。
	addCasterLayoutRequest.MixList = []*string{tea.String("RV01")}   // ビデオの位置。

	audioLayer := &live20161101.AddCasterLayoutRequestAudioLayer{}
	audioLayer.VolumeRate = tea.Float32(1)
	audioLayer.ValidChannel = tea.String("all")
	audioLayer.FixedDelayDuration = tea.Int32(0)

	addCasterLayoutRequest.AudioLayer = []*live20161101.AddCasterLayoutRequestAudioLayer{
		audioLayer,
	}

	videoLayer := &live20161101.AddCasterLayoutRequestVideoLayer{
		FillMode:           tea.String("fit"),
		HeightNormalized:   tea.Float32(1),
		WidthNormalized:    tea.Float32(1),
		PositionRefer:      tea.String("topLeft"),
		PositionNormalized: []*float32{tea.Float32(0), tea.Float32(0)},
		FixedDelayDuration: tea.Int32(0),
	}

	addCasterLayoutRequest.VideoLayer = []*live20161101.AddCasterLayoutRequestVideoLayer{
		videoLayer,
	}
	addCasterLayoutResponse, err := liveClient.AddCasterLayout(addCasterLayoutRequest)
	if err != nil {
		return nil, errors.New("AddCasterLayout failed: " + err.Error())
	}
	return addCasterLayoutResponse, nil
}

// リアルタイム字幕コンポーネントを追加してシーンに適用します。
func AddETComponent(liveClient *live20161101.Client, casterId *string, layoutId *string, pgmSceneId *string) error {
	// 前提条件: プロダクションスタジオが作成され、ライブストリームがビデオソースとして追加され、locationID が RV01 であること。
	// 注: リアルタイム字幕はライブストリームでのみ有効です。
	// コンポーネントを作成します。
	r := &live20161101.AddCasterComponentRequest{
		CasterId:       casterId,
		ComponentType:  tea.String("caption"),
		ComponentName:  tea.String("Real-time subtitles for testing"),
		Effect:         tea.String("none"),
		LocationId:     tea.String("RV01"),
		ComponentLayer: tea.String(`{"HeightNormalized":"1","WidthNormalized":"1","PositionRefer":"topLeft","PositionNormalized":["0.05", "0.7"]}`),
		// 字幕フィールドの詳細については、AddCasterComponent トピックの CaptionLayerContent パラメーターの説明をご参照ください。
		// 次のフィールドが追加されます。公式ドキュメントは更新されていないことにご注意ください。
		// BoxWidthNormalized: テキストのバックグラウンドの正規化された幅。この値はフォントサイズに基づいて計算されます (boxWidth/font_size)。計算値が 16 を超える場合は、値 16 が使用されます。デフォルト値: 0。
		// BoxColor: テキストのバックグラウンドの色。値は 0xRGBA フォーマットです。たとえば、0xff0000ff は不透明な赤を示します。デフォルト値は "" で、このパラメーターが無効であることを示します。
		// ShadowxWidthNormalized: テキストの網掛けの x 座標の正規化された値。この値はフォントサイズに基づいて計算されます (shadowxWidth/font_size)。計算値が 16 を超える場合は、値 16 が使用されます。デフォルト値: 0。
		// ShadowyWidthNormalized: テキストの網掛けの y 座標の正規化された値。この値はフォントサイズに基づいて計算されます (shadowyWidth/font_size)。計算値が 16 を超える場合は、値 16 が使用されます。デフォルト値: 0。
		// ShadowColor: テキストの網掛けの色。値は 0xRGBA フォーマットです。たとえば、0xff0000ff は不透明な赤を示します。デフォルト値は "" で、このパラメーターが無効であることを示します。
		CaptionLayerContent: tea.String(`{
        "SizeNormalized": 0.05,
        "Color": "0xFFFFFF",
        "LocationId": "RV01",
        "BorderColor": "0x696969",
        "BorderWidthNormalized": 0.1,
        "BoxColor": "0xffffff",
        "BoxWidthNormalized": 0.7,
        "ShadowColor": "0x3c3c3c",
        "ShadowxWidthNormalized": 0.4,
        "ShadowyWidthNormalized": 0.4,
        "SourceLan": "cn",
        "TargetLan": "en",
        "PtsOffset": -1000,
        "SourceLanPerLineWordCount": 28,
        "TargetLanPerLineWordCount": 60,
        "ShowSourceLan": true,
        "ShowTargetLan": true,
        "Truncation": false,
        "AppearDuration": 20000,
        "AppearMode": "Movie"
        }`),
	}

	addCasterComponentResp, err := liveClient.AddCasterComponent(r)
	if err != nil {
		return errors.New("AddCasterComponent failed: " + err.Error())
	}

	// 指定したシーンにコンポーネントを適用します。
	setCasterSceneConfigRequest := &live20161101.UpdateCasterSceneConfigRequest{
		CasterId:    casterId,
		LayoutId:    layoutId,
		SceneId:     pgmSceneId,
		ComponentId: []*string{addCasterComponentResp.Body.ComponentId},
	}

	_, err = liveClient.UpdateCasterSceneConfig(setCasterSceneConfigRequest)
	if err != nil {
		return errors.New("UpdateCasterSceneConfig failed: " + err.Error())
	}
	return nil
}

// プロダクションスタジオを開始して再生シーンを設定します。
func StartCaster(liveClient *live20161101.Client, casterId *string, layoutId *string) (*live20161101.StartCasterResponse, error) {
	// プロダクションスタジオを開始します。
	startCasterRequest := &live20161101.StartCasterRequest{
		CasterId: casterId,
	}
	startCasterResp, err := liveClient.StartCaster(startCasterRequest)
	if err != nil {
		return nil, errors.New("StartCaster failed: " + err.Error())
	}

	// リソースの読み込みには時間がかかります。プロダクションスタジオをすぐに開始すると、リソースの読み込みに失敗する可能性があります。そのため、しばらくプロセスを一時停止する必要があります。
	time.Sleep(time.Second)

	// 再生シーンを設定します。
	// PVW (オプション)
	setCasterSceneConfigRequest := &live20161101.SetCasterSceneConfigRequest{
		CasterId: casterId,
		LayoutId: layoutId,
		SceneId:  startCasterResp.Body.PvwSceneInfos.SceneInfo[0].SceneId,
	}

	_, err = liveClient.SetCasterSceneConfig(setCasterSceneConfigRequest)
	if err != nil {
		return nil, errors.New("SetCasterSceneConfig failed: " + err.Error())
	}
	// PGM (必須)
	setCasterSceneConfigRequest.SceneId = startCasterResp.Body.PgmSceneInfos.SceneInfo[0].SceneId
	_, err = liveClient.SetCasterSceneConfig(setCasterSceneConfigRequest)
	if err != nil {
		return nil, errors.New("SetCasterSceneConfig failed: " + err.Error())
	}
	return startCasterResp, nil
}

// レイアウトを切り替えます。
func ChangeLayout(liveClient *live20161101.Client, casterId *string, pgmSceneId *string, newLayoutId *string) error {
	// シーンのレイアウト ID を変更します。
	setCasterSceneConfigRequest := &live20161101.UpdateCasterSceneConfigRequest{
		CasterId: casterId,
		SceneId:  pgmSceneId,
		LayoutId: newLayoutId,
	}
	_, err := liveClient.UpdateCasterSceneConfig(setCasterSceneConfigRequest)
	if err != nil {
		return errors.New("UpdateCasterSceneConfig failed: " + err.Error())
	}
	return nil
}

// プロダクションスタジオを停止します。
func StopCaster(liveClient *live20161101.Client, casterId *string) error {
	stopCasterRequest := &live20161101.StopCasterRequest{
		CasterId: casterId,
	}
	_, err := liveClient.StopCaster(stopCasterRequest)
	if err != nil {
		return errors.New("StopCaster failed: " + err.Error())
	}
	return nil
}

// プロダクションスタジオを削除します。
func DeleteCaster(liveClient *live20161101.Client, casterId *string) error {
	deleteCasterRequest := &live20161101.DeleteCasterRequest{
		CasterId: casterId,
	}
	_, err := liveClient.DeleteCaster(deleteCasterRequest)
	if err != nil {
		return errors.New("DeleteCaster failed: " + err.Error())
	}
	return nil
}

func main() {
	liveClient, err := GetClientInstance()
	if err != nil {
		panic(err)
	}
	// プロダクションスタジオを作成します。
	createCasterResponse, err := CreateCaster(liveClient)
	if err != nil {
		panic(err)
	}
	casterId := createCasterResponse.Body.CasterId
	log.Println("CasterId: ", *casterId)

	// プロダクションスタジオを設定します。
	domainName := tea.String("example.aliyundoc.com") // ドメイン名を設定します。
	SetCasterConfig(liveClient, casterId, domainName)

	// ビデオソースを追加します。関数内でビデオソースを追加する必要があります。
	AddCasterVideoResource(liveClient, casterId)

	// レイアウトを追加します。
	addCasterLayoutResponse, err := AddCasterLayout(liveClient, casterId)
	if err != nil {
		panic(err)
	}
	layoutId := addCasterLayoutResponse.Body.LayoutId

	// プロダクションスタジオを開始して再生シーンを設定します。
	startCasterResp, err := StartCaster(liveClient, casterId, layoutId)
	if err != nil {
		panic(err)
	}

	// (オプション) リアルタイム字幕コンポーネントを追加して PGM シーンに適用します。
	pgmSceneId := startCasterResp.Body.PgmSceneInfos.SceneInfo[0].SceneId
	AddETComponent(liveClient, casterId, layoutId, pgmSceneId)

	// (オプション) レイアウトを切り替えます。
	// newLayoutId := tea.String("xxxx")
	// ChangeLayout(liveClient, casterId, pgmSceneId, newLayoutId)

	time.Sleep(time.Minute * 10)
	// プロダクションスタジオを停止します。
	StopCaster(liveClient, casterId)

	// プロダクションスタジオを削除します。
	DeleteCaster(liveClient, casterId)
}