Skip to content

recursivecodes/ivs-cloud-cards

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

16 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

AWS Cloud Cards - Amazon Interactive Video Service

Online Reference

This document is an online companion to the AWS Cloud Cards deck for Amazon Interactive Video Service (Amazon IVS).

Table of Contents

πŸ‘‹ Welcome To Cloud Cards!

🀘 IVS Rocks!

⭐️ Live Streaming Made Easy

Code Samples

$ aws ivs create-channel --name low-latency-demo
import { IvsClient, CreateChannelCommand } 
  from '@aws-sdk/client-ivs';
const client = new IvsClient();
const createChannelInput = {
  'name': 'low-latency-demo',
  'type': 'STANDARD',
}
const command = new CreateChannelCommand(createChannelInput);
const response = await client.send(command);

πŸ’ͺ Save It For Later (Low-Latency)

Code

# create S3 bucket
$ aws s3 mb s3://ivs-demo-recording-bucket
# create recording config
$ aws ivs create-recording-configuration \
  --name demo-config \
  --destination-configuration '{
    "s3": {
      "bucketName": "ivs-demo-recording-bucket"
    }
  }' \
  --thumbnail-configuration '{
    "recordingMode": "INTERVAL",
    "targetIntervalSeconds": 30,
    "storage": ["LATEST"],
  }'
#create channel, associate new recording config
$ aws ivs create-channel \
  --name recorded-channel-demo \
  --recording-configuration-arn [RECORDING_CONFIG_ARN]

πŸ’ͺ Change The Channel

Code

$ aws ivs create-channel \
  --name low-latency-demo \
  --type STANDARD

πŸ’ͺ Members Only

Code

$ openssl ecparam -name secp384r1 -genkey -noout -out priv.pem
$ openssl ec -in priv.pem -pubout -out public.pem
$ aws ivs import-playback-key-pair \
  --public-key-material "`cat public.pem`"
$ aws ivs create-channel --authorized

πŸ’ͺ Flexible Ingest

Code

$ ffmpeg -re -stream_loop -1 \
  -i $VIDEO_FILEPATH -r 30 \
  -c:v libx264 -pix_fmt yuv420p \
  -profile:v main -preset veryfast \
  -x264opts "nal-hrd=cbr:no-scenecut" \
  -minrate 3000 -maxrate 3000 -g 60 \
  -c:a aac -b:a 160k -ac 2 -ar 44100 \
  -f flv rtmps://$INGEST_ENDPOINT:443/app/$STREAM_KEY
$ export URI="srt://$INGEST_ENDPOINT:9000"
$ URI="$URI?streamid=$STREAM_KEY"
$ URI="$URI&passphrase=$PASSPHRASE"
$ ffmpeg -re -i $VIDEO_FILEPATH -c copy -f mpegts $URI

πŸ’ͺ Equal Access

Code

$ git clone https://github.com/aws-samples/\
amazon-ivs-webgpu-captions-demo.git

# initialize the infrastructure
$ npm run deploy:init

# deploy the backend stack
$ npm run deploy:backend

# run the client app
$ npm ci
$ npm run dev

# deploy the client app (optional)
$ npm run deploy:website

πŸ’ͺ What Time Is It?

Code

$ aws ivs put-metadata \
  --channel-arn "[CHANNEL_ARN]" \
  --metadata "test metadata"
const videoEl = document.getElementById('video-player');
const streamUrl = '[PLAYBACK_URL]';
const ivsPlayer = IVSPlayer.create();
ivsPlayer.attachHTMLVideoElement(videoEl);
ivsPlayer.load(streamUrl);
ivsPlayer.play();

const evt = IVSPlayer.PlayerEventType.TEXT_METADATA_CUE;
ivsPlayer.addEventListener(evt, (metadata) => {
  console.log(metadata);
})

πŸ’ͺ No Pirates!

Code

$ aws ivs create-playback-restriction-policy \
  --name demo-policy \
  --enable-strict-origin-enforcement \
  --allowed-countries "US", "JP" \
  --allowed-origins "https://example.com"
# add policy to channel
$ aws ivs update-channel \
  --arn [CHANNEL_ARN] \
  --playback-restriction-policy-arn [POLICY_ARN]

πŸ’ͺ No Interruptions

⭐️ Welcome To The Stage!

Code

$ aws ivs-realtime create-stage --name real-time-demo
$ aws ivs-realtime create-stage --name real-time-demo \
  --participant-token-configurations '[{"userId": "1"}]'
import { IvsRealTimeClient, CreateStageCommand } 
  from "@aws-sdk-client-ivs-realtime";

const client = new IvsRealTimeClient();
const input = {
  name: 'real-time-demo',
  participantTokenConfigurations: [
    {
      userId: "1",
    }
  ]
};
const command = new CreateStageCommand(input);
const response = await client.send(command);

πŸ’ͺ Extended Reach (Part 1)

πŸ’ͺ Extended Reach (Part 2)

Code

$ aws ivs-realtime create-encoder-configuration \
  --name demo-encoder-configuration \
  --video "bitrate=25000000,height=720,width=1280,framerate=30"
$ aws ivs-realtime start-composition \
  --stage-arn [REAL_TIME_STAGE_ARN] \
  --destination '[
    {
      "channel": {
        "channelArn": "[LOW_LATENCY_CHANNEL_ARN]",
        "encoderConfigurationArn": "[ENCODER_CONFIG_ARN]"
      }
    }
  ]'

πŸ’ͺ Save It For Later (Real-Time)

Code

$ aws ivs-realtime create-storage-configuration \
  --name demo-storage-config \
  --s3 "bucket=demo-recording-bucket"
$ aws ivs-realtime create-encoder-configuration \
  --name demo-encoder-configuration \
  --video "bitrate=6000000,height=1080,width=1920,framerate=60"
$ aws ivs-realtime start-composition \
  --stage-arn "[STAGE_ARN]" \
  --destination '[{
    "s3": {
      "encoderConfigurationArn": ["[ENCODER_CONFIG_ARN]"],
      "storageConfigurationArn": "[STORAGE_CONFIG_ARN]"
    }
  }]
  '

πŸ’ͺ WHIP It Up!

πŸ’ͺ Perfect Timing

Code

const config = {
  inBandMessaging: { enabled: true }
};
const stream = new LocalStageStream(videoTrack, config);
const payload = new TextEncoder().encode('test').buffer;
stream.insertSeiMessage(payload);
const strategy = {
    subscribeConfiguration: (participant) => {
        return { inBandMessaging: { enabled: true } };
    }
    // ... other strategy functions
}
stage.on(StageEvents.STAGE_STREAM_SEI_MESSAGE_RECEIVED, 
  (participant, seiMessage) => {
    console.log(seiMessage.payload, seiMessage.uuid);
});
{"timestamp":"...","event":"card_dealt","seat":2,"card":"7H","face_up":true}
{"timestamp":"...","event":"card_dealt","seat":4,"card":"6S","face_up":true}
{"timestamp":"...","event":"card_dealt","card":"3S","face_up":true}
{"timestamp":"...","event":"card_dealt","seat":2,"card":"5H","face_up":true}
{"timestamp":"...","event":"card_dealt","seat":4,"card":"10H","face_up":true}
{"timestamp":"...","event":"card_dealt","card":"4S","face_up":false}
{"timestamp":"...","event":"prompt_player","seat":4}
{"timestamp":"...","event":"player_action","seat":4,"action":"hit"}
{"timestamp":"...","event":"card_dealt","seat":4,"card":"4S","face_up":false}
{"timestamp":"...","event":"prompt_player","seat":4}
{"timestamp":"...","event":"player_action","seat":4,"action":"stand"}
{"timestamp":"...","event":"prompt_player","seat":2}
{"timestamp":"...","event":"player_action","seat":2,"action":"hit"}
{"timestamp":"...","event":"card_dealt","seat":2,"card":"JS","face_up":false}
{"timestamp":"...","event":"prompt_player","seat":2}
{"timestamp":"...","event":"player_action","seat":2,"action":"stay"}
{"timestamp":"...","event":"dealer_reveal","card":"4S"}

πŸ’ͺ Alternative Ingest

Code

$ aws ivs-realtime create-ingest-configuration \
  --name demo-ingest-config \
  --stage-arn "[STAGE_ARN]" \
  --ingest-protocol RTMPS

πŸ’ͺ Real Time, Real Quality

Code

let cameraStream = new LocalStageStream(
  cameraDevice,
  {
    simulcast: { enabled: true }
  }
);
const initialLayerPreference: InitialLayerPreference.LOWEST_QUALITY;
const strategy = {
    subscribeConfiguration: (participant) => {
        return {
            simulcast: {
                initialLayerPreference
            }
        }
    },
    preferredLayerForStream: (participant, stream) => {
      return stream.getLowestQualityLayer();
    }
    // ... other strategy functions
}

⭐️ Hey Chat!

Code

$ aws ivschat create-room --name chat
$ aws ivschat create-chat-token \
  --room-identifier "[CHAT_ARN]" \
  --user-id "1" \
  --capabilities "SEND_MESSAGE"
const token = "[CHAT_TOKEN]";
const endpoint = "[CHAT_ENDPOINT]";
const connection = new WebSocket(endpoint, token);
const payload = {
  "Action": "SEND_MESSAGE",
  "Content": "text message",
}
connection.send(JSON.stringify(payload));
connection.onmessage = (event) => {
  const message = JSON.parse(event.data);
  console.log(message);
}

πŸ’ͺ Watch What You Say!

Code

{
   "Content": "string",
   "MessageId": "string",
   "RoomArn": "string",
   "Attributes": {"string": "string"},
   "Sender": {
      "Attributes": { "string": "string" },
      "UserId": "string",
      "Ip": "string"
   }
}
{
   "Content": "string",
   "ReviewResult": "string",
   "Attributes": {"string": "string"},
}
"Attributes": { "Reason": "denied for moderation" }
$ aws ivschat create-room \
  --name demo-chat \
  --message-review-handler '
    {
      "fallbackResult": "DENY",
      "uri": "[LAMBDA_ARN]",
    }
  '

πŸ’ͺ Remember What They Said

Code

$ aws logs create-log-group --log-group-name demo-chat-cw-logs
$ aws ivschat create-logging-configuration \
  --name demo-chat-log  \
  --destination-configuration '
    {
      "cloudWatchLogs": {
        "logGroupName" : "demo-chat-cw-logs"
      }
    }
  '
$ aws ivschat create-room \
  --name demo-chat  \
  --logging-configuration-identifiers "[LOGGING_CONFIG_ARN]"
$ aws s3 mb s3://demo-chat-s3-logs
$ aws ivschat create-logging-configuration \
  --name demo-chat-log  \
  --destination-configuration '
    {
      "s3": {
        "bucketName" : "demo-chat-s3-logs"
      }
    }
  '
# create firehose delivery stream first...
$ aws ivschat create-logging-configuration \
  --name demo-chat-log  \
  --destination-configuration '
    {
      "firehose": {
        "deliveryStreamName" : "demo-chat-firehose-stream"
      }
    }
  '

☁️ Amazon CloudWatch

☁️ Amazon EventBridge

Code

export const handler = async (event) => {
  console.log(`
    Received: '${event["detail-type"]}'
    named '${event.detail.event_name}'
    at ${event.time}
    on channel ${event.detail.channel_name}
    with stream id ${event.detail.stream_id}.
  `);
}
# create rule
$ aws events put-rule  \
  --name demo-ivs-event \
  --event-pattern "{\"source\": [\"aws.ivs\"]}" \
  --state ENABLED
# add permission to invoke lambda
$ aws lambda add-permission \
  --function-name ivs-demo-function \
  --statement-id EventBridgeInvoke \
  --action lambda:InvokeFunction \
  --principal events.amazonaws.com \
  --source-arn [RULE_ARN]
# add lambda function as target for rule
$ aws events put-targets --rule demo-ivs-rule \
  --targets '{"Id": "1", "Arn": "[LAMBDA_ARN]"}'

☁️ AWS CloudTrail

☁️ Amazon S3

☁️ AWS AppSync

Code

$ aws appsync create-api \
  --name demo-event-api \
  --event-config '
    {
      "authProviders": [{"authType": "API_KEY"}],
      "connectionAuthModes": [{"authType": "API_KEY"}],
      "defaultPublishAuthModes": [{"authType": "API_KEY"}],
      "defaultSubscribeAuthModes": [{"authType": "API_KEY"}]
    }'
$ aws appsync create-api-key --api-id [API_ID]
$ aws appsync create-channel-namespace \
  --name default-api-ns \
  --api-id [API_ID]

πŸ§‘πŸ½β€πŸ’» Watch Anywhere

Code

const videoEl = document.getElementById('video-player');
const streamUrl = '[PLAYBACK_URL]';
const ivsPlayer = IVSPlayer.create();
ivsPlayer.attachHTMLVideoElement(videoEl);
ivsPlayer.load(streamUrl);
ivsPlayer.play();

πŸ§‘πŸ½β€πŸ’» Streaming On The Go

Code

<canvas id="preview"></canvas>

<script type="module">
  const streamKey = '[STREAM_KEY]';
  const ingestEndpoint = '[INGEST_ENDPOINT]';
  const streamConfig = IVSBroadcastClient.STANDARD_LANDSCAPE;
  const config = { streamConfig, ingestEndpoint };
  const client = IVSBroadcastClient.create(config);
  await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
  client.attachPreview(document.getElementById('preview'));
  const devices = await navigator.mediaDevices.enumerateDevices();
  const videoDevices = devices.filter(d => d.kind == 'videoinput');
  const audioDevices = devices.filter(d => d.kind == 'audioinput');
  const cameraStream = 
    await navigator.mediaDevices.getUserMedia({
      video: { 
        deviceId: videoDevices[0].deviceId,
        aspectRatio: 16 / 9,
      },
    });
  const microphoneStream = 
    await navigator.mediaDevices.getUserMedia({
      audio: { 
        deviceId: audioDevices[0].deviceId 
      },
    });
  client.addVideoInputDevice(cameraStream, 'camera1', { index: 0 });
  client.addAudioInputDevice(microphoneStream, 'mic1');
  client.startBroadcast(streamKey)
</script>

πŸ’‘ Let Them Cook

πŸ’‘ Place Your Bets

πŸ’‘ Learning Time

πŸ’‘ Can You Hear Me?

Code

$ git clone \
  https://github.com/aws-samples/amazon-ivs-real-time-audio-rooms-web-demo.git
$ cd amazon-ivs-real-time-audio-rooms-web-demo
$ npm run deploy:init
$ npm run deploy:backend:dev # for development
$ npm run deploy:backend:prod # for production
$ npm run deploy:website:dev # for development
$ npm run deploy:website:prod # for production
$ npm run dev

πŸ’‘ Shop Until You Drop

Code

# check out the project
$ git clone \
  https://github.com/aws-samples/\
amazon-ivs-real-time-basic-web-demo.git
$ cd amazon-ivs-real-time-basic-web-demo

# install required packages
$ npm ci

# run the deploy
# when the deployment successfully completes
# copy the url provided in the output
# you may need the url when running client app
$ npm run deploy

# retrieve the CloudFormation stack outputs
$ aws cloudformation describe-stacks \
  --stack-name AmazonIVSRtWebDemoStack \
  --query 'Stacks[].Outputs'

# cleanup (delete all resources associated 
# with this demo including DynamoDB table)
$ npm run destroy

πŸ’‘ Social Streaming

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published