

# Use the C\$1\$1 producer library
<a name="producer-sdk-cpp"></a>

You can use the Amazon Kinesis Video Streams provided C\$1\$1 producer library to write application code to send media data from a device to a Kinesis video stream. 

## Object model
<a name="producer-sdk-cpp-objectmodel"></a>

The C\$1\$1 library provides the following objects to manage sending data to a Kinesis video stream:
+ **KinesisVideoProducer:** Contains information about your media source and AWS credentials, and maintains callbacks to report on Kinesis Video Streams events.
+ **KinesisVideoStream:** Represents the Kinesis video stream. Contains information about the video stream's parameters, such as name, data retention period, and media content type.

## Put media into the stream
<a name="producer-sdk-cpp-putframe"></a>

You can use the C\$1\$1 library provided methods (for example, `PutFrame`) to put data into the `KinesisVideoStream` object. The library then manages the internal state of the data, which can include the following tasks: 
+ Performing authentication.
+ Watching for network latency. If the latency is too high, the library might choose to drop frames.
+ Tracking status of streaming in progress.

## Callback interfaces
<a name="producer-sdk-cpp-callbacks"></a>

This layer exposes a set of callback interfaces, which enable it to talk to the application layer. These callback interfaces include the following:


+ **Service callbacks interface (`CallbackProvider`): **The library invokes events obtained through this interface when it creates a stream, obtains a stream description, and deletes a stream.
+ **Client-ready state or low storage events interface (`ClientCallbackProvider`):** The library invokes events on this interface when the client is ready, or when it detects that it might run out of available storage or memory.
+ **Stream events callback interface (`StreamCallbackProvider`):** The library invokes events on this interface when stream events occur, such as the stream entering the ready state, dropped frames, or stream errors.

Kinesis Video Streams provides default implementations for these interfaces. You can also provide your own custom implementation—for example, if you need custom networking logic or you want to expose a low storage condition to the user interface.

For more information about callbacks in the producer libraries, see [Producer SDK callbacks](producer-reference-callbacks.md).

## Procedure: Use the C\$1\$1 producer SDK
<a name="producer-sdk-cpp-using"></a>

This procedure demonstrates how to use the Kinesis Video Streams client and media sources in a C\$1\$1 application to send data to your Kinesis video stream.

The procedure includes the following steps:

**Topics**

# Prerequisites
<a name="producer-sdk-cpp-prerequisites"></a>

Before you set up the C\$1\$1 producer SDK, ensure that you have the following prerequisites: 
+ **Credentials:** In the sample code, you provide credentials by specifying a profile that you set up in your AWS credentials profile file. If you haven't already done so, first set up your credentials profile. 

  For more information, see [Set up AWS Credentials and Region for Development](https://docs.aws.amazon.com//sdk-for-java/v1/developer-guide/setup-credentials.html).
+ **Certificate store integration:** The Kinesis Video Streams producer library must establish trust with the service it calls. This is done through validating the certificate authorities (CAs) in the public certificate store. On Linux-based models, this store is located in the `/etc/ssl`/ directory. 

  Download the certificate from the following location to your certificate store:

  [https://www.amazontrust.com/repository/SFSRootCAG2.pem](https://www.amazontrust.com/repository/SFSRootCAG2.pem)
+ Install the following build dependencies for macOS:
  + [Autoconf 2.69](http://www.gnu.org/software/autoconf/autoconf.html) (License GPLv3\$1/Autoconf: GNU GPL version 3 or later) 
  + [CMake 3.7 or 3.8](https://cmake.org/)
  + [Pkg-Config](https://www.freedesktop.org/wiki/Software/pkg-config/)
  + xCode (macOS) / clang / gcc (xcode-select version 2347)
  + Java Development Kit (JDK) (for Java JNI compilation)
  + [Lib-Pkg](https://github.com/freebsd/pkg/tree/master/libpkg)
+ Install the following build dependencies for Ubuntu:
  + Git: `sudo apt install git`
  + [CMake](http://kitware.com/cmake): `sudo apt install cmake`
  + G\$1\$1: `sudo apt install g++`
  + pkg-config: `sudo apt install pkg-config`
  + OpenJDK: `sudo apt install openjdk-8-jdk`
**Note**  
This is only required if you’re building Java Native Interface (JNI).
  + Set the `JAVA_HOME` environment variable: `export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/`

# Download and configure the C\$1\$1 producer library code
<a name="producersdk-cpp-download"></a>

For information about how to download and configure the C\$1\$1 producer library, see [Amazon Kinesis Video Streams CPP Producer, GStreamer Plugin and JNI](https://github.com/awslabs/amazon-kinesis-video-streams-producer-sdk-cpp).

For prerequisites and more information about this example, see [Use the C\$1\$1 producer library](producer-sdk-cpp.md).

## CMake arguments
<a name="cmake-arguments"></a>

Below is a reference table for the C\$1\$1 Producer SDK-specific CMake arguments. You can also pass the [standard CMake options](https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html) to CMake as well.

**Important**  
These are all optional.

**Flags for including or excluding certain features**


| CMake argument | Type | Default | Explanation | 
| --- | --- | --- | --- | 
| `BUILD_DEPENDENCIES` |  Boolean  |  ON  | Build dependencies from source. Otherwise, use the dependencies that are already installed on the system. If the one of the required dependencies couldn't be found, an error will be returned. | 
| `BUILD_GSTREAMER_PLUGIN` | Boolean |  OFF  | Builds the kvssink GStreamer plugin. | 
|  `BUILD_JNI`  | Boolean |  OFF  | Builds the Java Native Interface (JNI) to be able to call this code from a Java runtime environment. | 
|  `ALIGNED_MEMORY_MODEL`  | Boolean |  OFF  | If memory allocations should be aligned to 8-byte boundaries. Some architectures don't allow for unaligned memory access. | 
| `CONSTRAINED_DEVICE` | Boolean |  OFF  | Non-Windows only. When ON, sets the thread stack size to 0.5 MiB. Needed for [Alpine Linux](https://wiki.alpinelinux.org/wiki/Main_Page) builds. Otherwise, the operating system default is used. | 
|  `BUILD_STATIC`  | Boolean |  OFF  | Build libraries and executables as [shared](https://en.wikipedia.org/wiki/Shared_library) (OFF), or [static](https://en.wikipedia.org/wiki/Static_library) (ON). | 
|  `ADD_MUCLIBC`  | Boolean |  OFF  | Link to [uClibc](https://en.wikipedia.org/wiki/UClibc) instead of the standard C library, which is a smaller C standard library designed for embedded systems. | 
|  `OPEN_SRC_INSTALL_PREFIX`  |  String  | ../open-source/local | Location to install the open-source dependencies, if building from source. | 

**Flags for cross-compilation**

**Important**  
Set these if your target and host machine CPU architectures are different.


| CMake argument | Type | Default | Explanation | 
| --- | --- | --- | --- | 
| `BUILD_LOG4CPLUS_HOST` |  String  |  ""  | Build the log4cplus dependency for the specified CPU architecture. If not set, log4cplus will auto-detect and use the host machine's CPU architecture. | 
| `BUILD_OPENSSL_PLATFORM`  |  String  |  ""  | Build the OpenSSL dependency for the specified CPU architecture. If not set, OpenSSL will auto-detect and use the host machine's CPU architecture. | 

**Flags related to testing**


| CMake argument | Type | Default | Explanation | 
| --- | --- | --- | --- | 
| `BUILD_TEST` |  Boolean  |  OFF  | Build the unit and integration tests. To run all the tests, run ./tst/producerTest from the build directory. AWS Credentials are needed to run the tests. | 
| `CODE_COVERAGE` | Boolean | OFF | Only available for GNU/Clang compilers. Enable code coverage collection with [gcov](https://gcc.gnu.org/onlinedocs/gcc/Gcov.html) and report generation. | 
| `COMPILER_WARNINGS` | Boolean | OFF | Only available for GNU/Clang compilers. Enable all compiler warnings. | 
| `ADDRESS_SANITIZER` | Boolean | OFF | Only available for GNU/Clang compilers. Build with [AddressSanitizer](https://compiler-rt.llvm.org/). | 
| `MEMORY_SANITIZER` | Boolean | OFF | Only available for GNU/Clang compilers. Build with [MemorySanitizer](https://compiler-rt.llvm.org/). | 
| `THREAD_SANITIZER` | Boolean | OFF | Only available for GNU/Clang compilers. Build with [ThreadSanitizer](https://compiler-rt.llvm.org/). | 
| `UNDEFINED_BEHAVIOR_SANITIZER` | Boolean | OFF | Only available for GNU/Clang compilers. Build with [UndefinedBehaviorSanitizer](https://compiler-rt.llvm.org/). | 

To use these CMake arguments, pass them as a space-separated list of `-Dkey=value` pairs following the `cmake ..` command. For example:

```
cmake .. -DBUILD_GSTREAMER_PLUGIN=ON -DBUILD_DEPENDENCIES=OFF -DALIGNED_MEMORY_MODEL=ON 
```

CMake will look for the compiler toolchain by following the `$PATH` variable. Before running CMake, set the `CC` and `CXX` environment variables to explicitly set the toolchain to use for cross compiling.

# Write and examine the code
<a name="producersdk-cpp-write"></a>

In this section of the [Use the C\$1\$1 producer library](producer-sdk-cpp.md), you examine the code in the C\$1\$1 test harness (`tst/ProducerTestFixture.h` and other files). You downloaded this code in the previous section.

The **Platform Independent** C\$1\$1 example shows the following coding pattern:
+ Create an instance of `KinesisVideoProducer` to access Kinesis Video Streams.
+ Create an instance of `KinesisVideoStream`. This creates a Kinesis video stream in your AWS account if a stream of the same name doesn't already exist.
+ Call `putFrame` on the `KinesisVideoStream` for every frame of data, as it becomes available, to send it to the stream.

The following sections provide more information about this coding pattern.



## Create an instance of KinesisVideoProducer
<a name="producersdk-cpp-write-create-producer"></a>

You create the `KinesisVideoProducer` object by calling the `KinesisVideoProducer::createSync` method. The following example creates the `KinesisVideoProducer` in the `ProducerTestFixture.h` file:

```
kinesis_video_producer_ = KinesisVideoProducer::createSync(move(device_provider_),
    move(client_callback_provider_),
    move(stream_callback_provider_),
    move(credential_provider_),
    defaultRegion_);
```

The `createSync` method takes the following parameters:
+ A `DeviceInfoProvider` object, which returns a `DeviceInfo` object containing information about the device or storage configuration.
**Note**  
You configure your content store size using the `deviceInfo.storageInfo.storageSize` parameter. Your content streams share the content store. To determine your storage size requirement, multiply the average frame size by the number of frames stored for the max duration for all the streams. Then multiply by 1.2 to account for defragmentation. For example, suppose that your application has the following configuration:  
Three streams
3 minutes of maximum duration
Each stream is 30 frames per second (FPS)
Each frame is 10,000 KB in size
The content store requirement for this application is **3 (streams) \$1 3 (minutes) \$1 60 (seconds in a minute) \$1 10000 (kb) \$1 1.2 (defragmentation allowance) = 194.4 Mb \$1 200 Mb**.
+ A `ClientCallbackProvider` object, which returns function pointers that report client-specific events.
+ A `StreamCallbackProvider` object, which returns function pointers that are called back when stream-specific events occur.
+ A `CredentialProvider` object, which provides access to AWS credential environment variables.
+ The AWS Region ("us-west-2"). The service endpoint is determined from the Region.

## Create an instance of KinesisVideoStream
<a name="producersdk-cpp-write-create-stream"></a>

You create the `KinesisVideoStream` object by calling the `KinesisVideoProducer::CreateStream` method with a `StreamDefinition` parameter. The example creates the `KinesisVideoStream` in the `ProducerTestFixture.h` file with the track type as video, and with track id as 1:

```
auto stream_definition = make_unique<StreamDefinition>(stream_name,
                                               hours(2),
                                               tags,
                                               "",
                                               STREAMING_TYPE_REALTIME,
                                               "video/h264",
                                               milliseconds::zero(),
                                               seconds(2),
                                               milliseconds(1),
                                               true,
                                               true,
                                               true);
return kinesis_video_producer_->createStream(move(stream_definition));
```

The `StreamDefinition` object has the following fields:
+ Stream name.
+ Data retention period.
+ Tags for the stream. These tags can be used by consumer applications to find the correct stream, or to get more information about the stream. The tags can also be viewed in the AWS Management Console.
+ AWS KMS encryption key for the stream. For more information, see [Data protection in Kinesis Video Streams](how-kms.md).
+ Streaming type. Currently, the only valid value is `STREAMING_TYPE_REALTIME`.
+ Media content type.
+ Media latency. This value isn't currently used, and should be set to 0.
+ Playback duration of each fragment.
+ Media timecode scale.
+ Whether the media uses key frame fragmentation.
+ Whether the media uses timecodes.
+ Whether the media uses absolute fragment times.

## Add an audio track to the Kinesis video stream
<a name="producersdk-cpp-write-add-audiotrack-to-stream"></a>

You can add audio track details to a video track stream definition by using the `addTrack` method of the `StreamDefinition`:

```
stream_definition->addTrack(DEFAULT_AUDIO_TRACKID, DEFAULT_AUDIO_TRACK_NAME, DEFAULT_AUDIO_CODEC_ID, MKV_TRACK_INFO_TYPE_AUDIO);
```

The `addTrack` method requires the following parameters:
+ Track id (as one for audio). This should be unique and non-zero value.
+ User-defined track name (for example, "audio" for the audio track). 
+ Codec id for this track (for example, for audio track "A\$1AAC").
+ Track type (for example, use the enum value of MKV\$1TRACK\$1INFO\$1TYPE\$1AUDIO for audio). 

If you have codec private data for the audio track, then you can pass it when calling the addTrack function. You can also send the codec private data after creating the KinesisVideoStream object while calling the start method in KinesisVideoStream.

## Put a frame into the Kinesis video stream
<a name="producersdk-cpp-write-putframe"></a>

You put media into the Kinesis video stream using `KinesisVideoStream::putFrame`, passing in a `Frame` object that contains the header and media data. The example calls `putFrame` in the `ProducerApiTest.cpp` file:

```
frame.duration = FRAME_DURATION_IN_MICROS * HUNDREDS_OF_NANOS_IN_A_MICROSECOND;
    frame.size = SIZEOF(frameBuffer_);
    frame.frameData = frameBuffer_;
    MEMSET(frame.frameData, 0x55, frame.size);

    while (!stop_producer_) {
        // Produce frames
        timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
                std::chrono::system_clock::now().time_since_epoch()).count() / DEFAULT_TIME_UNIT_IN_NANOS;
        frame.index = index++;
        frame.decodingTs = timestamp;
        frame.presentationTs = timestamp;

        // Key frame every 50th
        frame.flags = (frame.index % 50 == 0) ? FRAME_FLAG_KEY_FRAME : FRAME_FLAG_NONE;
    ...

    EXPECT_TRUE(kinesis_video_stream->putFrame(frame));
```

**Note**  
The preceding C\$1\$1 producer example sends a buffer of test data. In a real-world application, you should obtain the frame buffer and size from the frame data from a media source (such as a camera).

The `Frame` object has the following fields:
+ Frame index. This should be a monotonically incrementing value.
+ Flags associated with the frame. For example, if the encoder were configured to produce a key frame, this frame would be assigned the `FRAME_FLAG_KEY_FRAME` flag.
+ Decoding timestamp.
+ Presentation timestamp.
+ Duration of the frame (to 100 ns units).
+ Size of the frame in bytes.
+ Frame data.

For more information about the format of the frame, see [Kinesis Video Streams data model](how-data.md).

## Put a KinesisVideoFrame into a specific track of KinesisVideoStream
<a name="producersdk-cpp-write-putframeintospecifictrack"></a>

You can use the `PutFrameHelper` class to put frame data into a specific track. First, call the `getFrameDataBuffer` to get a pointer to one of the pre-allocated buffers to fill in the `KinesisVideoFrame` data. Then, you can call the `putFrameMultiTrack` to send the `KinesisVideoFrame` along with the Boolean value to indicate the type of frame data. Use true if it's a video data or false if the frame contains audio data. The `putFrameMultiTrack` method uses a queueing mechanism to ensure that the MKV Fragments maintain monotonically increasing frame timestamps and any two fragments don't overlap. For example, the MKV timestamp of the first frame of a fragment should always be greater than the MKV timestamp of the last frame of the previous fragment. 

The `PutFrameHelper` has the following fields:
+ Maximum number of audio frames in the queue. 
+ Maximum number of video frames in the queue.
+ Size to allocate for a single audio frame.
+ Size to allocate for a single video frame.

## Access metrics and metric logging
<a name="producersdk-cpp-write-metrics"></a>

The C\$1\$1 producer SDK includes functionality for metrics and metric logging. 

You can use the `getKinesisVideoMetrics` and `getKinesisVideoStreamMetrics` API operations to retrieve information about Kinesis Video Streams and your active streams.

The following code is from the `kinesis-video-pic/src/client/include/com/amazonaws/kinesis/video/client/Include.h` file.

```
/**
* Gets information about the storage availability.
*
* @param 1 CLIENT_HANDLE - the client object handle.
* @param 2 PKinesisVideoMetrics - OUT - Kinesis Video metrics to be filled.
*
* @return Status of the function call.
*/
PUBLIC_API STATUS getKinesisVideoMetrics(CLIENT_HANDLE, PKinesisVideoMetrics);

/**
* Gets information about the stream content view.
*
* @param 1 STREAM_HANDLE - the stream object handle.
* @param 2 PStreamMetrics - Stream metrics to fill.
*
* @return Status of the function call.
*/
PUBLIC_API STATUS getKinesisVideoStreamMetrics(STREAM_HANDLE, PStreamMetrics);
```

The `PClientMetrics` object filled by `getKinesisVideoMetrics` contains the following information:
+ **contentStoreSize:** The overall size in bytes of the content store (the memory used to store streaming data).
+ **contentStoreAvailableSize:** The available memory in the content store, in bytes.
+ **contentStoreAllocatedSize:** The allocated memory in the content store.
+ **totalContentViewsSize:** The total memory used for the content view. The content view is a series of indices of information in the content store.
+ **totalFrameRate:** The aggregate number of frames per second across all active streams.
+ **totalTransferRate:** The total bits per second (bps) being sent in all streams.

The `PStreamMetrics` object filled by `getKinesisVideoStreamMetrics` contains the following information:
+ **currentViewDuration:** The difference in 100 ns units between the head of the content view (when frames are encoded) and the current position (when frame data is sent to Kinesis Video Streams).
+ **overallViewDuration:** The difference in 100 ns units between the head of the content view (when frames are encoded) to the tail (when frames are flushed from memory, either because the total allocated space for the content view is exceeded, or because a `PersistedAck` message is received from Kinesis Video Streams, and frames known to be persisted are flushed).
+ **currentViewSize:** The size in bytes of the content view from the head (when frames are encoded) to the current position (when frames are sent to Kinesis Video Streams).
+ **overallViewSize:** The total size in bytes of the content view.
+ **currentFrameRate:** The last measured rate of the stream, in frames per second.
+ **currentTransferRate:** The last measured rate of the stream, in bytes per second.

## Teardown
<a name="producersdk-cpp-write-teardown"></a>

If you want to send the remaining bytes in a buffer and wait for the `ACK`, you can use `stopSync`:

```
kinesis_video_stream->stopSync();            
```

Or you can call `stop` to end the streaming: 

```
kinesis_video_stream->stop();            
```

After stopping the stream, you can free the stream through invoking the following API:

```
kinesis_video_producer_->freeStream(kinesis_video_stream);            
```

# Run and verify the code
<a name="producersdk-cpp-test"></a>

To run and verify the code for the [Use the C\$1\$1 producer library](producer-sdk-cpp.md), see the following OS-specific instructions:
+ [Linux](https://github.com/awslabs/amazon-kinesis-video-streams-producer-sdk-cpp/blob/master/docs/linux.md)
+ [macOS](https://github.com/awslabs/amazon-kinesis-video-streams-producer-sdk-cpp/blob/master/docs/macos.md)
+ [Windows](https://github.com/awslabs/amazon-kinesis-video-streams-producer-sdk-cpp/blob/master/docs/windows.md)
+ [Raspberry Pi OS](https://github.com/awslabs/amazon-kinesis-video-streams-producer-sdk-cpp/blob/master/docs/raspberry-pi.md)

You can monitor the traffic on your stream by watching the metrics that are associated with your stream in the Amazon CloudWatch console, such as `PutMedia.IncomingBytes`.

# Use the C\$1\$1 producer SDK as a GStreamer plugin
<a name="producer-sdk-cpp-gstreamer"></a>

[GStreamer](https://gstreamer.freedesktop.org/) is a popular media framework used by multiple cameras and video sources to create custom media pipelines by combining modular plugins. The Kinesis Video Streams GStreamer plugin streamlines the integration of your existing GStreamer media pipeline with Kinesis Video Streams. 

For information about using the C\$1\$1 producer SDK as a GStreamer plugin, see [Example: Kinesis Video Streams producer SDK GStreamer Plugin - kvssink](examples-gstreamer-plugin.md).

# Use the C\$1\$1 producer SDK as a GStreamer plugin in a Docker container
<a name="producer-sdk-cpp-gstreamer-docker"></a>

[GStreamer](https://gstreamer.freedesktop.org/) is a popular media framework used by multiple cameras and video sources to create custom media pipelines by combining modular plugins. The Kinesis Video Streams GStreamer plugin streamlines the integration of your existing GStreamer media pipeline with Kinesis Video Streams. 

In addition, using [Docker]() to create the GStreamer pipeline standardizes the operating environment for Kinesis Video Streams, which streamlines building and running the application.

For information about using the C\$1\$1 producer SDK as a GStreamer plugin in a Docker container, see [Run the GStreamer element in a Docker container](examples-gstreamer-plugin.md#examples-gstreamer-plugin-docker).

# Use logging with the C\$1\$1 producer SDK
<a name="producer-sdk-cpp-logging"></a>

You configure logging for C\$1\$1 producer SDK applications in the `kvs_log_configuration` file in the `kinesis-video-native-build` folder.

The following example shows the first line of the default configuration file, which configures the application to write `DEBUG`-level log entries to the AWS Management Console:

```
log4cplus.rootLogger=DEBUG, KvsConsoleAppender
```

You can set the logging level to `INFO` for less verbose logging.

To configure the application to write log entries to a log file, update the first line in the file to the following:

```
log4cplus.rootLogger=DEBUG, KvsConsoleAppender, KvsFileAppender
```

This configures the application to write log entries to `kvs.log` in the `kinesis-video-native-build/log` folder.

To change the log file location, update the following line with the new path:

```
log4cplus.appender.KvsFileAppender.File=./log/kvs.log
```

**Note**  
If `DEBUG`-level logging is written to a file, the log file can use up the available storage space on the device quickly.