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, create an XStxClientLibraryHandle object by using the XStxClientLibraryCreate function. The XStxClientLibraryHandle object 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 initXStxClient function of AppStreamSampleClientViewController.m.

Copy
-(XStxResult) initXStxClient { XStxResult createResult = XSTX_RESULT_OK; /// create Singleton of client library handle createResult = XStxClientLibraryCreate(XSTX_CLIENT_API_VERSION_MAJOR, XSTX_CLIENT_API_VERSION_MINOR, &mClientLibraryHandle); if (createResult != XSTX_RESULT_OK) { [self printResult:createResult withMessage:@"XStxClientLibraryCreate failed"]; return createResult; } return XSTX_RESULT_OK; }

The function creates a client library handle (clientLibraryHandle) that the client will use to create a client object. The client then creates a client object by calling the XStxClientCreate(mClientLibraryHandle function with the client library handle. The function returns a handle to the client.

The following excerpt from the example client in the Amazon AppStream SDK illustrates this step. The excerpt is from the connectXStxClient function of AppStreamSampleClientViewController.m.

Copy
// Create a XStx Client instance result = XStxClientCreate(mClientLibraryHandle, &mClientHandle); if (result != XSTX_RESULT_OK) { [self printResult:result withMessage:@"XStxClientCreate failed"]; return; }

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

The following excerpt from the example client in the Amazon AppStream SDK illustrates this step. The excerpt is from the H264ToYuv::init function of H264to Yuv.cpp.

Copy
/** initialize */ XStxResult H264ToYuv::init() { AvHelper::initialize(); AVCodec *codec = avcodec_find_decoder(CODEC_ID_H264); if(NULL == codec) { return XSTX_RESULT_AUDIO_DECODER_NULL; } mCodecContext = avcodec_alloc_context3(codec); if(NULL == mCodecContext) { return XSTX_RESULT_VIDEO_DECODING_ERROR; } mCodecContext->codec_type = AVMEDIA_TYPE_VIDEO; mCodecContext->codec_id = CODEC_ID_H264; mCodecContext->pix_fmt = PIX_FMT_YUV420P; if(avcodec_open2(mCodecContext, codec,NULL) < 0) { return XSTX_RESULT_VIDEO_DECODING_ERROR; } av_init_packet(&mAvPacket); return XSTX_RESULT_OK; }

After populating the structure, call a function to configure a listener for callback functions.

The following excerpt from the example client in the Amazon AppStream SDK illustrates this step. The excerpt is from the clientReady function of AppStreamSampleClientViewController.m.

Copy
// start a client listener if ((result = XStxClientSetListener(mClientHandle, &mClientListener)) != XSTX_RESULT_OK) { [self printResult:result withMessage:@"XStxClientSetListener failed"]; 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.m.

Copy
bool VideoModule::initialize(XStxClientHandle mClientHandle, VideoDecoder* decoder, GLKView & rw) { // initialize frame allocator if(decoder == nil) { return false; } mDecoder = decoder; 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; } mRenderer = &rw; mStxRenderer.mRenderVideoFrameFcn = &renderFrame; mStxRenderer.mRenderVideoFrameCtx = this; mStxRenderer.mSetMaxResolutionFcn = &rendererMaxResolution; mStxRenderer.mSetMaxResolutionCtx = this; mStxRenderer.mSize = sizeof(mStxRenderer); if (XStxClientSetVideoRenderer(mClientHandle, &mStxRenderer) != XSTX_RESULT_OK) { printf("Failed to set VideoRenderer.\n"); return false; } ((GLViewManager *)mRenderer.delegate).decodeType = mDecoder->getDecodeType(); 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; } return true; }

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.m.

Copy
/** * Initialize audio module * @param[in] clientHandle handle to XStx client */ bool AudioModule::initialize(XStxClientHandle clientHandle) { 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("XStxClientSetAudioFrameAllocator() failed.\n"); return false; } // initialize decoder mDecoder = new (std::nothrow) OpusToPcm(); if (!mDecoder) { printf("Failed to create audio decoder.\n"); return false; } mStxDecoder.mStartFcn = &decoderStart; mStxDecoder.mStartCtx = mDecoder; mStxDecoder.mDecodeAudioFrameFcn = &decoderDecodeFrame; mStxDecoder.mDecodeAudioFrameCtx = mDecoder; mStxDecoder.mSize = sizeof(mStxDecoder); if (XStxClientSetAudioDecoder(clientHandle, &mStxDecoder) != XSTX_RESULT_OK) { printf("XStxClientSetAudioDecoder() failed.\n"); return false; } // initialize renderer mRenderer = new (std::nothrow) AudioRenderer(mFramePool, clientHandle); if (!mRenderer) { return false; } mStxRenderer.mStartFcn = &start; mStxRenderer.mStartCtx = mRenderer; mStxRenderer.mSize = sizeof(mStxRenderer); if (XStxClientSetAudioRenderer(clientHandle, &mStxRenderer) != XSTX_RESULT_OK) { printf("XStxClientSetAudioRenderer() failed. \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 a function with the Entitlement URL.

The following excerpt from the example client in the Amazon AppStream SDK illustrates this step. The excerpt is from the connectXStxClient function in AppStreamSampleClientViewController.m.

Copy
if ((result = XStxClientSetEntitlementUrl(mClientHandle, [url UTF8String])) != XSTX_RESULT_OK) { [self printResult:result withMessage:@"XStxClientSetEntitlementUrl failed"]; return; }

The client starts a session by calling the XStxClientStart function.

The following excerpt from the example client in the Amazon AppStream SDK illustrates this step. The excerpt is from the connectXStxClient function in AppStreamSampleClientViewController.m.

Copy
// this method is non-blocking // defer XStxClientLibraryRecycle call for unload methods if ((result = XStxClientStart(mClientHandle)) != XSTX_RESULT_OK) { [self printResult:result withMessage:@"XStxClientStart failed"]; return; } NSString *message = [NSString stringWithFormat:@"STX client initialized. Connecting to %@:",url]; [self printResult:result withMessage:message]; [self hideBackground]; [self setupInputs];