4K Resolution in Amazon AppStream 2.0
Published: 2023-09-18 12:52:04



## Introduction

Amazon AppStream 2.0, a fully managed application streaming service, has recently introduced support for 4K resolution. This enhancement promises a significant upgrade for users who require high-definition visuals for their applications. But why is 4K resolution a pivotal addition to AppStream, and how can you deploy it using CloudFormation? Let's explore.

## Why we need 4K resolution?

For the Professionals: Think of graphic designers working on intricate artwork, video editors piecing together 4K footage, architects visualizing detailed structures, or medical professionals analyzing high-res medical images.If they want to stream those applications using AppStream, 4K support is quite important.

Sharper, Clearer, More Detailed: With 4096 x 2160 pixels, 4K offers four times the pixel density of Full HD. This means applications on AppStream will now look crisper.

Elevated User Experience: Even for normal users, With 4K , Texts are sharper, icons pop out, and visuals are just a treat to the eyes. It's all about offering an unmatched user experience.


## Lets stream your application in 4K

Before you jump into the 4K bandwagon, here are a few things to keep in mind:

- Must use AppStream Client: Make sure you're using the latest AppStream Windows client.Go to this [link](https://clients.amazonappstream.com/) to download Appstream Client 
- Choose the Graphic Instances: 4K is gorgeous but demands its fair share of resources. Opt for `on-demand` or `always-on` **graphic instances** to ensure smooth streaming.You cannot use AppStream `elastic` fleet(No server-less unfortunately) 

### Quick guide to deploy:

1) First you need to create an Image Builder.This is a required step to create a Custom image which includes your application and configurations.

```
AWSTemplateFormatVersion: '2010-09-09'
Description: AppStream 2.0 Custom Image Builder
Parameters:
  InstanceType:
    Type: String
    Default: stream.graphics-design.xlarge
  ImageBuilderName:
    Type: String
    Default: 4KImageBuilder
  VpcId:
    Type: AWS::EC2::VPC::Id
  Subnet1Id:
    Type: AWS::EC2::Subnet::Id
Resources:
  AppStreamImageBuilder:
    Type: 'AWS::AppStream::ImageBuilder'
    Properties:
      Name: !Ref ImageBuilderName
      InstanceType: !Ref InstanceType
      ImageArn: !Sub arn:aws:appstream:${AWS::Region}::image/AppStream-Graphics-Design-WinServer2019-06-12-2023
      IamRoleArn: !GetAtt AppStreamIAMRole.Arn
      EnableDefaultInternetAccess: false
      DisplayName: 4K image builder
      Description: 4K image builder
      VpcConfig:
        SecurityGroupIds: 
          - !Ref AppStreamSecurityGroup
        SubnetIds:
          - !Ref Subnet1Id
  AppStreamSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: AppStream Security Group
      SecurityGroupIngress:
        - IpProtocol: -1
          CidrIp: 10.0.0.0/8
      VpcId: !Ref VpcId
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-SecurityGroup"
  AppStreamIAMRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: appstream.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonAppStreamServiceAccess
      Policies:
        - PolicyName: AppStreamIAMPolicy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action: s3:*
                Resource:
                  - "arn:aws:s3:::appstream*/*"
```
This template will create the image builder.

2)Connect to AppStream Image Builder instance and install and configure the application.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ybap02fbi269wt74csuw.png)

More info: https://docs.aws.amazon.com/appstream2/latest/developerguide/managing-image-builders-connect.html

3) Using Image Assistant, create an Appstream Image called `4k-appstream-app` which is used to define Appstream fleet in next step. You may replace variables according to your application in following script and run it script inside the Image builder to create the image.
```
  ##*===============================================
    ##* APPSTREAM VARIABLE DECLARATION
    ##*===============================================
    [string]$AppName = '4k-appstream-app'
    [string]$AppPath = 'C:\4k-appstream-app\4k-appstream-app.exe'
    [string]$AppDisplayName = '4k-appstream-app'
    [string]$AppParameters = ''
    [string]$AppWorkingDir = ''
    [string]$AppIconPath =  ''
    [string]$ManifestPath = "C:\Users\ImageBuilderAdmin\Documents\optimization_manifest.txt"
     
    [string]$ImageAssistantPath = "C:\Program Files\Amazon\Photon\ConsoleImageBuilder\image-assistant.exe"
 
    ##*===============================================
    ##* ADD APPLICATION TO APPSTREAM CATALOG
    ##*===============================================
    #AppStream's Image Assistant Required Parameters
    $Params = " --name " + $AppName + " --absolute-app-path """ + $AppPath + """"     
 
    #AppStream's Image Assistant Optional Parameters
    if ($AppDisplayName) { $Params += " --display-name """ + $AppDisplayName + """" }
    if ($AppWorkingDir) { $Params += " --working-directory """ + $AppWorkingDir + """" }
    if ($AppIconPath) { $Params += " --absolute-icon-path """ + $AppIconPath + """" }      
    if ($AppParameters) { $Params += " --launch-parameters """ + $AppParameters + """" }     
    if ($ManifestPath) { $Params += " --absolute-manifest-path """ + $ManifestPath + """" }
 
    #Escape spaces in EXE path
    $ImageAssistantPath = $ImageAssistantPath -replace ' ','` '
 
    #Assemble Image Assistant API command to add applications
    $AddAppCMD = $ImageAssistantPath + ' add-application' + $Params
 
    Write-Host "Adding $AppDisplayName to AppStream Image Catalog using command $AddAppCMD"
 
    #Run Image Assistant command and parameters
    $AddApp = Invoke-Expression $AddAppCMD | ConvertFrom-Json
    if ($AddApp.status -eq 0) {
        Write-Host "SUCCESS adding $AppName to the AppStream catalog."
    } else {
        Write-Host "ERROR adding $AppName to the AppStream catalog." 
        Write-Host $AddApp.message
 
    }
    #AppStream's Image Assistant Required Parameters
    $Params = " --name " + $AppName + " --display-name  """ + $AppName + """"     
 
    #Assemble Image Assistant API command to add applications
    $CreateImgCMD = $ImageAssistantPath + ' create-image' + $Params
 
    Write-Host "Creating image $AppName using command $CreateImgCMD"
 
    #Run Image Assistant command and parameters
    $createImg = Invoke-Expression $CreateImgCMD | ConvertFrom-Json
    if ($createImg.status -eq 0) {
        Write-Host "SUCCESS creating image $AppName"
    } else {
        Write-Host "ERROR creating image $AppName" 
        Write-Host $createImg.message
 
  }
```
Once you run the script successfully you will notice image created `4k-appstream-app` under Appstream images.

4) Deploy AppStream fleet and Stack using Cloudformation template 

```
AWSTemplateFormatVersion: 2010-09-09
Description: "Provision AppStream 2.0 Fleet and Stack"
Parameters:
  FleetName:
    Type: String

  FleetInstanceType:
    Type: String
    Default: stream.graphics-design.large

  StackName:
    Type: String
 
  SecurityGroupId:
    Type: String
    Default: ""

  VpcId:
    Type: String

  Subnet1Id:
    Type: String

  Subnet2Id:
    Type: String

  FileUploadPermission:
    Type: String

  FileDownloadPermission:
    Type: String

  ClipboardCopyToLocalDevice:
    Type: String

  ClipboardCopyFromLocalDevice:
    Type: String

  PrintingToLocalDevice:
    Type: String
      

Conditions:
  SecurityGroupIdNotGiven: !Equals [!Ref SecurityGroupId, ""]

Resources:
  4KAppStreamFleet:
    Type: AWS::AppStream::Fleet
    Properties:
      Name: !Ref FleetName
      ComputeCapacity:
        DesiredInstances: 1
      InstanceType: !Ref FleetInstanceType
      # replace the Image Arn of previously created Image
      ImageArn: !Sub arn:aws:appstream:${AWS::Region}:${AWS::AccountId}:image/4k-appstream
      FleetType: "ON_DEMAND"
      VpcConfig:
        SecurityGroupIds:
          - !If [
              SecurityGroupIdNotGiven,
              !Ref AppStreamSecurityGroup,
              !Ref SecurityGroupId,
            ]
        SubnetIds:
          - !Ref Subnet1Id
          - !Ref Subnet2Id
      EnableDefaultInternetAccess: False
      MaxUserDurationInSeconds: "57600"
      DisconnectTimeoutInSeconds: "900"
      IdleDisconnectTimeoutInSeconds: "900"
      StreamView: APP
    CreationPolicy:
      StartFleet: True

  AppStreamSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: AppStream Security Group
      SecurityGroupIngress:
        - IpProtocol: -1
          CidrIp: 10.0.0.0/8
      VpcId: !Ref VpcId
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-SecurityGroup"

  # Create AppStream Stack
  AppStreamStack:
    Type: AWS::AppStream::Stack
    Properties:
      Name: !Ref StackName
      Description: This demo stack was created using CloudFormation
      ApplicationSettings:
        Enabled: false
      UserSettings:
        - Action: CLIPBOARD_COPY_TO_LOCAL_DEVICE
          Permission: !Ref ClipboardCopyToLocalDevice
        - Action: FILE_DOWNLOAD
          Permission: !Ref FileDownloadPermission
        - Action: FILE_UPLOAD
          Permission: !Ref FileUploadPermission
        - Action: CLIPBOARD_COPY_FROM_LOCAL_DEVICE
          Permission: !Ref ClipboardCopyFromLocalDevice
        - Action: PRINTING_TO_LOCAL_DEVICE
          Permission: !Ref PrintingToLocalDevice

  # Create Association between fleet and stack
  4KAppStreamDemoStackFleetAssociation:
    Type: AWS::AppStream::StackFleetAssociation
    Properties:
      FleetName: !Ref 4KAppStreamFleet
      StackName: !Ref AppStreamStack

```

6) Launch Appstream URL using AppStream Windows client

You have to base64 encode the AppStream url and add `amazonappstream:` so you can launch the application from Browser using AppStream client.You may use code similar to following to covert your AppStream url, so that it will launch the AppStream session through AppStream Client.

```
function stringToBase64WithPrefix(appstreamUrl: string): string {
    const base64Encoded=Buffer.from(appstreamUrl).toString('base64');
    return `amazonappstream:${base64Encoded}`
}
```

Once you launch your AppStream session using Appstream URL, you should be able to see the option in AppStream menu to change the resolution to 4K.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k5jjm078m7u6ip9e6nyf.png)