Menu
Amazon AppStream
Developer Guide

This documentation is for an older version of Amazon AppStream. For information about the latest version, see the Amazon AppStream 2.0 Developer Guide.

Creating Your Client

To create a client, your client must create an XStxClientLibraryHandle object. This is the top level object that you will use to interact with the libraries you will use to connect to sessions, render the audio and video, and send inputs to the application.

The following excerpt from the example client in the Amazon AppStream SDK illustrates this step. The excerpt is from the main function of XStxExampleClient.cpp.

Copy
/** instantiate client library handle */ XStxClientLibraryHandle clientLibraryHandle; XStxResult createResult = XSTX_RESULT_OK; if ((createResult = XStxClientLibraryCreate( XSTX_CLIENT_API_VERSION_MAJOR, XSTX_CLIENT_API_VERSION_MINOR, &clientLibraryHandle)) != XSTX_RESULT_OK) { const char * name; const char * desc; XStxResultGetInfo(createResult, &name, &desc); printf("XStxClientLibraryCreate failed with: %s\n", name); return 1; }

The function creates a client library handle (clientLibraryHandle) that the client will use to create a client object. The example client creates the client object by instantiating an object from a user-defined class.

The following excerpt from the example client in the Amazon AppStream SDK illustrates this step. The excerpt is from the WindowListener class definition of XStxExampleClient.cpp.

Copy
// setup xstx client and start making the connection if ((result = XStxClientCreate(mClientLibraryHandle, &mClientHandle)) != XSTX_RESULT_OK) { mRenderWindow->setErrorText("Failed to create client"); const char * name; const char * desc; XStxResultGetInfo(result, &name, &desc); printf("XStxClientCreate failed with: %s\n", name); return; }

The object needs a structure to respond to the callback functions from the application. The client creates and populates a XStxIClientListener structure to respond to the callback functions.

The following excerpt from the example client in the Amazon AppStream SDK illustrates this step. The excerpt is from the readyForConnection function of XStxExampleClient.cpp.

Copy
... XStxIClientListener mStxListener; ... mStxListener.mClientReadyFcn = &clientReady; mStxListener.mClientReadyCtx = this; mStxListener.mClientStoppedFcn = &clientStopped; mStxListener.mClientStoppedCtx = this; mStxListener.mMessageReceivedFcn = &messageReceived; mStxListener.mMessageReceivedCtx = this;

After populating the structure, call the XStxClientSetListener function to configure a listener that responds to the callback functions.

The following excerpt from the example client in the Amazon AppStream SDK illustrates this step. The excerpt is from the readyForConnection function of XStxExampleClient.cpp.

Copy
if ((result = XStxClientSetListener(mClientHandle, &mStxListener)) != XSTX_RESULT_OK) { mRenderWindow->setErrorText("Failed to set listener"); const char * name; const char * desc; XStxResultGetInfo(result, &name, &desc); printf("XStxClientSetListener failed with: %s\n", name); return; }

The client uses structures to get, render, and decode video and audio frames. The next step is to create and populate these structures. The example client instantiates a class to create and populate the structures.

To handle a video frame, the client create and populate the following structures defined in VideoModule.h:

  • XStxIVideoDecoder. Used to get and decode a video frame.

  • XStxIVideoRenderer. Used to render a video frame.

  • XStxIRawVideoFrameAllocator. Used to get and recycle a video frame.

The following excerpt from the example client in the Amazon AppStream SDK illustrates populating the structures for video. The excerpt is from VideoModule.cpp.

Copy
/** * Initialize video module * @param[in] clientHandle handle to XStx client * @param[in] rw renderer */ bool VideoModule::initialize(XStxClientHandle mClientHandle, RenderWindow & rw) { // initialize frame allocator mStxFrameAllocator.mInitFcn = &allocatorInit; mStxFrameAllocator.mInitCtx = this; mStxFrameAllocator.mGetVideoFrameBufferFcn = &allocatorGetFrame; mStxFrameAllocator.mGetVideoFrameBufferCtx = this; mStxFrameAllocator.mRecycleVideoFrameBufferFcn = &allocatorRecycleFrame; mStxFrameAllocator.mRecycleVideoFrameBufferCtx = this; mStxFrameAllocator.mSize = sizeof(mStxFrameAllocator); if (XStxClientSetVideoFrameAllocator(mClientHandle, &mStxFrameAllocator) != XSTX_RESULT_OK) { printf("Failed to SetVideoFrameAllocator.\n"); return false; } // initialize renderer mRenderer = &rw; mStxRenderer.mRenderVideoFrameFcn = &renderFrame; mStxRenderer.mRenderVideoFrameCtx = mRenderer; mStxRenderer.mSetMaxResolutionFcn = &rendererMaxResolution; mStxRenderer.mSetMaxResolutionCtx = mRenderer; mStxRenderer.mSize = sizeof(mStxRenderer); if (XStxClientSetVideoRenderer(mClientHandle, &mStxRenderer) != XSTX_RESULT_OK) { printf("Failed to set SetVideoRenderer.\n"); return false; } // initialize decoder mDecoder = new H264ToYuv(); if (!mDecoder) { return false; } mStxDecoder.mGetCapabilitiesCtx = mDecoder; mStxDecoder.mGetCapabilitiesFcn = &videoDecoderGetCapabilities; mStxDecoder.mDecodeVideoFrameFcn = &decodeFrame; mStxDecoder.mDecodeVideoFrameCtx = mDecoder; mStxDecoder.mStartFcn = &videoDecoderStart; mStxDecoder.mStartCtx = mDecoder; mStxDecoder.mSize = sizeof(mStxDecoder); if (XStxClientSetVideoDecoder(mClientHandle, &mStxDecoder) != XSTX_RESULT_OK) { printf("Failed to set SetVideoDecoder.\n"); return false; }

To handle an audio frame, the client create and populate the following structures defined in AudioModule.h:

  • XStxIAudioDecoder. Used to get and decode an audio frame.

  • XStxIAudioRenderer. Used to render an audio frame.

  • XStxIRawAudioFrameAllocator. Used to get and recycle an audio frame.

The following excerpt from the example client in the Amazon AppStream SDK illustrates populating the structures for audio. The excerpt is from AudioModule.cpp.

Copy
/** * Initialize audio module * @param[in] clientHandle handle to XStx client */ bool AudioModule::initialize(XStxClientHandle clientHandle) { // initialize frame allocator mStxFrameAllocator.mInitFcn = &allocatorInit; mStxFrameAllocator.mInitCtx = this; mStxFrameAllocator.mGetAudioFrameBufferFcn = &allocatorGetFrame; mStxFrameAllocator.mGetAudioFrameBufferCtx = this; mStxFrameAllocator.mRecycleAudioFrameBufferFcn = &allocatorRecycleFrame; mStxFrameAllocator.mRecycleAudioFrameBufferCtx = this; mStxFrameAllocator.mSize = sizeof(mStxFrameAllocator); if (XStxClientSetAudioFrameAllocator(clientHandle, &mStxFrameAllocator) != XSTX_RESULT_OK) { printf("Failed to SetAudioFrameAllocator\n"); return false; } // initialize decoder mDecoder = new (std::nothrow) OpusToPcm(); if (!mDecoder) { printf("Failed to create Decoder\n"); return false; } mStxDecoder.mDecodeAudioFrameFcn = &decoderDecodeFrame; mStxDecoder.mDecodeAudioFrameCtx = mDecoder; mStxDecoder.mStartFcn = &decoderStart; mStxDecoder.mStartCtx = mDecoder; mStxDecoder.mSize = sizeof(mStxDecoder); if (XStxClientSetAudioDecoder(clientHandle, &mStxDecoder) != XSTX_RESULT_OK) { printf("Failed to SetAudioDecoder\n"); return false; } // initialize renderer mRenderer = new (std::nothrow) AudioRenderer(mFramePool, clientHandle); if (!mRenderer) { return false; } // Set XStx callbacks and contexts on for the XStxIAudioRenderer struct mStxRenderer.mStartFcn = &start; mStxRenderer.mStartCtx = mRenderer; mStxRenderer.mSize = sizeof(mStxRenderer); // set the XStxIAudioRenderer to be used with the given clientHandle if (XStxClientSetAudioRenderer(clientHandle, &mStxRenderer) != XSTX_RESULT_OK) { printf("Failed to SetAudioRenderer\n"); return false; } return true; }

The client is now ready to configure and start a session with the application. The client configures a session by calling the XStxClientSetEntitlementUrl function with the endpoint of the entitlement service.

The following excerpt from the example client in the Amazon AppStream SDK illustrates this step. The excerpt is from the readyForConnection function in XStxExampleClient.cpp.

Copy
if ((result = XStxClientSetEntitlementUrl( mClientHandle, mEntitlementUrl.c_str())) != XSTX_RESULT_OK) { mRenderWindow->setErrorText("Failed to set entitlement URL"); const char * name; const char * desc; XStxResultGetInfo(result, &name, &desc); printf("XStxClientSetEntitlementUrl failed with: %s\n", name); return; }

The client starts a session by calling a function.

The following excerpt from the example client in the Amazon AppStream SDK illustrates this step. The excerpt is from the readyForConnection function in XStxExampleClient.cpp.

Copy
// non-blocking! if ((result = XStxClientStart(mClientHandle)) != XSTX_RESULT_OK) { mRenderWindow->setErrorText("Failed to start client"); const char * name; const char * desc; XStxResultGetInfo(result, &name, &desc); printf("XStxClientStart failed with: %s\n", name); return; } // success ! mRenderWindow->setErrorText("Starting STX");