SDK Version 2.0.1
AnsuR Technologies ASMIRA SDK
Loading...
Searching...
No Matches
example_complete.cpp

This is a minimal but complete example using ASMIRA SDK.

This is a minimal but complete example using ASMIRA SDK

#include <asmirasdk.h>
#include <string>
#include <thread>
#include <chrono>
#ifdef USE_STB_IMAGE_WRITE
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb_image_write.h>
static void WriteImage(const char* filename, const uint8_t* data,
const uint32_t width, const uint32_t height)
{
stbi_write_png(filename, width, height, 3, data, width * 3);
}
#endif
enum RoomJoinedState {
RoomJoinedStateUndef,
RoomJoinedStateReceivedList,
RoomJoinedStatePending,
RoomJoinedStateSuccess,
RoomJoinedStateError
};
enum State {
StateDisconnect,
StateConnect,
StateConnecting,
StateRequestRooms,
StateRequestRoomsPending,
StateRequestJoinRoomPending,
StateReady
};
struct context_s {
RoomJoinedState roomJoinedState = RoomJoinedStateUndef;
uint16_t clientRoomID = 0;
bool chatGreetingSent = false;
uint32_t audioSamplesReceived = 0;
// Files announced in the room, downloaded one at a time as they show up
uint64_t pendingFileHash = 0;
uint32_t pendingFileRoomID = 0;
State state = StateDisconnect;
asdk::sdk_t* sdk = nullptr;
// A real application clears this from its UI or a signal handler to shut down
bool running = true;
const uint16_t serverPort = 30100;
};
static bool Connect(context_s& context)
{
#ifdef EXAMPLE_TLS
// The certificate service listens one port above the secured server port
if (context.sdk->RequestCertificate("127.0.0.1", (uint16_t)(context.serverPort + 1),
"test", "password", &state, &cert) == asdk::StatusOK) {
puts("Connecting to server...");
if (context.sdk->ConnectSecured("127.0.0.1", context.serverPort, 5000, true,
"test", "password", asdk::UserCapabilityViewer,
"Test User") == asdk::StatusOK) {
puts("Connected to server");
return true;
}
else
printf("Failed to connect to server: %s\n", context.sdk->errorStr);
}
else
printf("Failed to request certificate(%d): %s\n", state, context.sdk->errorStr);
#else
if (context.sdk->Connect("127.0.0.1", context.serverPort, 5000, true, "test", "password",
"Test User") == asdk::StatusOK) {
puts("Connected to server");
return true;
}
else
printf("Failed to connect to server: %s\n", context.sdk->errorStr);
#endif
std::this_thread::sleep_for(std::chrono::seconds(1));
return false;
}
static bool RequestRooms(context_s& context)
{
return context.sdk->SendRequest(asdk::RequestRoomListSubscribe) == asdk::StatusOK;
}
static bool JoinRoom(context_s& context, const char *roomName)
{
return context.sdk->SendRequestStr(asdk::RequestRoomJoin, roomName) == asdk::StatusOK;
}
int main()
{
context_s context;
context.sdk = asdk::Initialize();
if (context.sdk) {
context.sdk->SetAuthenticateResponseCallback([](const asdk::AuthenticationResponse response,
void* opaque /* context* */) {
context_s* context = reinterpret_cast<context_s*>(opaque);
puts("Server authenticated your connection");
}
else {
context->serverState = asdk::ServerStateAuthenticateError;
printf("Server failed(%d) to authenticate your connection\n", response);
}
}, &context);
context.sdk->SetServerStateCallback([](const asdk::ServerState state, void* opaque /* context* */) {
reinterpret_cast<context_s*>(opaque)->serverState = state;
}, &context);
context.sdk->SetRoomAnnounceCallback([](const char* roomName, const uint32_t roomID,
const asdk::RoomStateValue state,
const asdk::RoomFlagValue flags,
void* opaque /* context* */) {
// Got first room, there may be many more
reinterpret_cast<context_s*>(opaque)->roomJoinedState = RoomJoinedStateReceivedList;
printf("Room(%s) with ID(%d) announced\n", roomName, roomID);
}, &context);
context.sdk->SetRoomResponseCallback([](const asdk::Request request, const asdk::RoomResponse response,
const void* optionalData, const uint32_t optionalDataSize,
void* opaque /* context* */) {
context_s* context = reinterpret_cast<context_s*>(opaque);
if (response == asdk::RoomResponseSuccess) {
context->roomJoinedState = RoomJoinedStateSuccess;
if (optionalData && optionalDataSize == sizeof(uint16_t)) {
context->clientRoomID = *reinterpret_cast<const uint16_t*>(optionalData);
context->state = StateReady;
printf("Joined room and got asigned ID(%d)\n", context->clientRoomID);
}
else {
context->roomJoinedState = RoomJoinedStateError;
puts("Failed to join room");
}
}
else
printf("Failed(%d) to join room on command(%d)\n", response, request);
}, &context);
context.sdk->SetRoomClientAddedCallback([](const uint32_t clientID, const char* userName,
const asdk::UserCapabilityValue userCapability,
const asdk::DeviceCapabilityValue deviceCapability,
void* opaque /* context* */) {
printf("Client(%d) with name(%s) added to room\n", clientID, userName);
}, & context);
context.sdk->SetRoomClientRemovedCallback([](const uint32_t clientID, void* opaque /* context* */) {
printf("Client(%d) removed from room\n", clientID);
}, & context);
context.sdk->SetChatMessageCallback([](const uint32_t clientID, const char* message,
const uint32_t size, void* opaque /* context* */) {
printf("Chat message from client(%d): %.*s\n", clientID, (int)size, message);
}, &context);
// A file was shared in the room, ask for it. RoomFileSendFromPath(roomID, path)
// shares one the other way, hashing and streaming it straight off disk.
context.sdk->SetRoomFileAvailableCallback([](const uint32_t roomID, const uint64_t hash,
const char* fileName, const uint32_t fileSize,
const uint32_t originClientID, const uint64_t utc,
void* opaque /* context* */) {
context_s* context = reinterpret_cast<context_s*>(opaque);
printf("Room(%d) offers \"%s\" of %d bytes\n", roomID, fileName, fileSize);
// Requested from the main loop, callbacks run on the SDK network thread
context->pendingFileRoomID = roomID;
context->pendingFileHash = hash;
}, &context);
context.sdk->SetRoomFileProgressCallback([](const uint32_t roomID, const uint64_t hash,
const char* fileName,
const asdk::RoomFileDirection direction,
const uint32_t transferred, const uint32_t total,
void* opaque /* context* */) {
printf("%s \"%s\" %d/%d bytes\n",
direction == asdk::RoomFileDirectionSend ? "Sending" : "Receiving",
fileName, transferred, total);
}, &context);
context.sdk->SetRoomFileDownloadedCallback([](const uint32_t roomID, const uint64_t hash,
const char* fileName, const uint8_t* data,
const uint32_t size,
void* opaque /* context* */) {
// Verified against the announced hash, valid for the duration of this call only
printf("Downloaded \"%s\" of %d bytes\n", fileName, size);
}, &context);
context.sdk->SetRoomFileSentCallback([](const uint32_t roomID, const uint64_t hash,
const char* fileName, void* opaque /* context* */) {
printf("Uploaded \"%s\", the room can download it now\n", fileName);
}, &context);
context.sdk->SetRoomFileErrorCallback([](const uint32_t roomID, const uint64_t hash,
const char* fileName, const asdk::RoomFileError error,
void* opaque /* context* */) {
printf("Transfer of \"%s\" failed(%d)\n", fileName, error);
}, &context);
context.sdk->SetRoomFileDeletedCallback([](const uint32_t roomID, const uint64_t hash,
void* opaque /* context* */) {
printf("A room file was deleted in room(%d)\n", roomID);
}, &context);
// Received audio is only decoded while this callback is set
context.sdk->SetDecodedAudioFrameCallback([](const asdk::audio_frame_t* audioFrame,
void* opaque /* context* */) {
// Mono signed 16 bit PCM, ready to hand to the playback device
context_s* context = reinterpret_cast<context_s*>(opaque);
context->audioSamplesReceived += audioFrame->sampleCount;
if (context->audioSamplesReceived >= audioFrame->sampleRate) {
context->audioSamplesReceived -= audioFrame->sampleRate;
puts("Received one second of room audio");
}
}, &context);
// Sending audio, from wherever the capture device delivers PCM:
// context.sdk->SendAudioFrame(samples, sampleCount); // 16 bit mono, AUDIO_SAMPLE_RATE
// context.sdk->FlushAudioFrames(); // when the talk burst ends
context.sdk->SetVideoModeCallback([](const asdk::video_mode_t* videoMode, void* opaque /* context* */) {
puts("Video mode changed");
}, &context);
context.sdk->SetVideoOptionsCallback([](const asdk::video_options_t* videoOptions, void* opaque /* context* */) {
puts("Video options changed");
}, &context);
context.sdk->SetFrameCallback([](const asdk::frame_t* frame, void* opaque /* context* */) {
#ifdef USE_STB_IMAGE_WRITE
WriteImage("frame.png", frame->data, frame->width, frame->height);
#endif // USE_STB_IMAGE_WRITE
}, &context);
context.sdk->SetEncodedStreamCallback([](const asdk::StreamType type, const void* data,
const uint32_t dataSize, void* opaque /* context* */) {
switch (type) {
break;
}
}, &context);
context.sdk->SetRoomPreviewImageCallback([](const uint32_t roomID, const uint64_t utc,
const asdk::ImageFormat imageFormat,
const uint8_t* data, const uint32_t size,
void* opaque /* context* */) {
printf("Room(%d) preview image received with format(%d) and size(%d)\n", roomID, imageFormat, size);
}, & context);
while (context.running) {
switch (context.state) {
case StateDisconnect:
context.state = StateConnect;
context.serverState = asdk::ServerStateUndef;
context.roomJoinedState = RoomJoinedStateUndef;
break;
case StateConnect:
if (Connect(context)) context.state = StateConnecting;
else context.state = StateDisconnect;
break;
case StateConnecting:
if (context.serverState == asdk::ServerStateConnectedAndAuthenticated) {
context.state = StateRequestRooms;
puts("Server authenticated your connection");
}
else if (context.serverState == asdk::ServerStateAuthenticateError) {
context.state = StateDisconnect;
puts("Server failed to authenticate your connection");
std::this_thread::sleep_for(std::chrono::seconds(5));
}
break;
case StateRequestRooms:
if (RequestRooms(context)) context.state = StateRequestRoomsPending;
else context.state = StateDisconnect;
break;
case StateRequestRoomsPending:
if (context.roomJoinedState == RoomJoinedStateReceivedList) {
if (JoinRoom(context, "test")) context.state = StateRequestJoinRoomPending;
else context.state = StateDisconnect;
}
break;
case StateRequestJoinRoomPending:
break;
case StateReady:
// Chat is room scoped, greet the room once it has been joined
if (!context.chatGreetingSent) {
context.chatGreetingSent = true;
if (context.sdk->SendChatMessage("Hello from the SDK example") != asdk::StatusOK)
printf("Failed to send chat message: %s\n", context.sdk->errorStr);
// Audio is optional, the codec is undefined without the audio module
asdk::audio_options_t audioOptions;
if (context.sdk->AudioOptions(&audioOptions) == asdk::StatusOK)
printf("Audio codec(%d) at %d bits per second\n", audioOptions.codec,
audioOptions.bitrate);
}
// Fetch whatever the room announced, connect with
// DeviceCapabilityFileTransfer for any of this to work
if (context.pendingFileHash != 0) {
const uint64_t hash = context.pendingFileHash;
context.pendingFileHash = 0;
if (context.sdk->RoomFileDownload(context.pendingFileRoomID,
hash) != asdk::StatusOK)
printf("Failed to start download: %s\n", context.sdk->errorStr);
}
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
context.sdk->Disconnect();
context.sdk->Unload();
}
return 0;
}
int DeviceCapabilityValue
Definition asmirasdk.h:404
CertificateState
Outcome of sdk_t::RequestCertificate.
Definition asmirasdk.h:784
AuthenticationResponse
Outcome of a login attempt, reported by AuthenticateResponseFunc.
Definition asmirasdk.h:194
ServerState
State of the connection to the server, reported by ServerStateFunc.
Definition asmirasdk.h:179
uint8_t UserCapabilityValue
Definition asmirasdk.h:351
@ CertificateStateUndef
Definition asmirasdk.h:785
@ UserCapabilityViewer
Definition asmirasdk.h:344
@ AuthenticationResponseSuccess
Definition asmirasdk.h:196
@ ServerStateAuthenticateError
Definition asmirasdk.h:184
@ ServerStateConnectedAndAuthenticated
Definition asmirasdk.h:183
@ ServerStateUndef
Definition asmirasdk.h:180
@ DeviceCapabilityBasic
Common baseline: H.265 video, Speex audio, microphone, WebP photo mode, ROI, chat and a display.
Definition asmirasdk.h:386
@ DeviceCapabilityFileTransfer
Definition asmirasdk.h:379
sdk_t * Initialize()
Loads the SDK shared library and creates an SDK handle.
Definition asmirasdk.h:1745
@ StatusOK
Definition asmirasdk.h:161
RoomFileError
Room file transfer failure reason.
Definition asmirasdk.h:283
RoomFileDirection
Room file transfer direction.
Definition asmirasdk.h:273
@ RoomFileDirectionSend
Definition asmirasdk.h:275
Request
Request sent with sdk_t::SendRequest or sdk_t::SendRequestStr.
Definition asmirasdk.h:213
uint32_t RoomStateValue
Definition asmirasdk.h:267
uint32_t RoomFlagValue
Definition asmirasdk.h:252
RoomResponse
Server answer to a Request, reported by RoomResponseFunc.
Definition asmirasdk.h:225
@ RequestRoomJoin
Definition asmirasdk.h:217
@ RequestRoomListSubscribe
Definition asmirasdk.h:215
@ RoomResponseSuccess
Definition asmirasdk.h:227
ImageFormat
Encoding of the image delivered by RoomPreviewImageFunc.
Definition asmirasdk.h:320
StreamType
Kind of payload delivered by EncodedStreamFunc.
Definition asmirasdk.h:304
@ StreamTypeAV1Frame
Definition asmirasdk.h:308
@ StreamTypeWEBP
Definition asmirasdk.h:310
@ StreamType264Frame
Definition asmirasdk.h:306
@ StreamTypeUnknown
Definition asmirasdk.h:305
@ StreamType265Frame
Definition asmirasdk.h:307
@ StreamTypeMPEGTS
Definition asmirasdk.h:309
struct asdk::sdk_t sdk_t
Decoded room audio, delivered by DecodedAudioFrameFunc.
Definition asmirasdk.h:575
uint32_t sampleCount
PCM samples in data.
Definition asmirasdk.h:576
uint32_t sampleRate
PCM sample rate, always AUDIO_SAMPLE_RATE.
Definition asmirasdk.h:577
Audio encoder settings, see sdk_t::SetAudioOptions and sdk_t::AudioOptions.
Definition asmirasdk.h:549
int32_t bitrate
Encoder target bitrate (bit/s).
Definition asmirasdk.h:551
AudioCodec codec
Encoder used by SendAudioFrame.
Definition asmirasdk.h:550
A server certificate, as filled in by sdk_t::RequestCertificate.
Definition asmirasdk.h:804
const char * data
Certificate data.
Definition asmirasdk.h:806
A decoded video or photo frame, delivered by FrameFunc.
Definition asmirasdk.h:459
int32_t height
Frame resolution height in pixels.
Definition asmirasdk.h:461
uint8_t * data
Frame RGB data (R8G8B8), width * height * 3 bytes.
Definition asmirasdk.h:465
int32_t width
Frame resolution width in pixels.
Definition asmirasdk.h:460
What the sending client is currently doing, delivered by VideoModeFunc.
Definition asmirasdk.h:525
Encoder settings in effect on the sending client, delivered by VideoOptionsFunc.
Definition asmirasdk.h:498