This is a minimal but complete example using ASMIRA SDK.
#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;
uint64_t pendingFileHash = 0;
uint32_t pendingFileRoomID = 0;
State state = StateDisconnect;
bool running = true;
const uint16_t serverPort = 30100;
};
static bool Connect(context_s& context)
{
#ifdef EXAMPLE_TLS
if (context.sdk->RequestCertificate("127.0.0.1", (uint16_t)(context.serverPort + 1),
puts("Connecting to server...");
if (context.sdk->ConnectSecured("127.0.0.1", context.serverPort, 5000, true,
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",
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)
{
}
static bool JoinRoom(context_s& context, const char *roomName)
{
}
int main()
{
context_s context;
if (context.sdk) {
void* opaque ) {
context_s* context = reinterpret_cast<context_s*>(opaque);
puts("Server authenticated your connection");
}
else {
printf("Server failed(%d) to authenticate your connection\n", response);
}
}, &context);
context.sdk->SetServerStateCallback([](
const asdk::ServerState state,
void* opaque ) {
reinterpret_cast<context_s*>(opaque)->serverState = state;
}, &context);
context.sdk->SetRoomAnnounceCallback([](const char* roomName, const uint32_t roomID,
void* opaque ) {
reinterpret_cast<context_s*>(opaque)->roomJoinedState = RoomJoinedStateReceivedList;
printf("Room(%s) with ID(%d) announced\n", roomName, roomID);
}, &context);
const void* optionalData, const uint32_t optionalDataSize,
void* opaque ) {
context_s* context = reinterpret_cast<context_s*>(opaque);
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,
void* opaque ) {
printf("Client(%d) with name(%s) added to room\n", clientID, userName);
}, & context);
context.sdk->SetRoomClientRemovedCallback([](const uint32_t clientID, void* opaque ) {
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 ) {
printf("Chat message from client(%d): %.*s\n", clientID, (int)size, message);
}, &context);
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_s* context = reinterpret_cast<context_s*>(opaque);
printf("Room(%d) offers \"%s\" of %d bytes\n", roomID, fileName, fileSize);
context->pendingFileRoomID = roomID;
context->pendingFileHash = hash;
}, &context);
context.sdk->SetRoomFileProgressCallback([](const uint32_t roomID, const uint64_t hash,
const char* fileName,
const uint32_t transferred, const uint32_t total,
void* opaque ) {
printf("%s \"%s\" %d/%d bytes\n",
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 ) {
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 ) {
printf("Uploaded \"%s\", the room can download it now\n", fileName);
}, &context);
context.sdk->SetRoomFileErrorCallback([](const uint32_t roomID, const uint64_t hash,
void* opaque ) {
printf("Transfer of \"%s\" failed(%d)\n", fileName, error);
}, &context);
context.sdk->SetRoomFileDeletedCallback([](const uint32_t roomID, const uint64_t hash,
void* opaque ) {
printf("A room file was deleted in room(%d)\n", roomID);
}, &context);
void* opaque ) {
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);
context.sdk->SetVideoModeCallback([](
const asdk::video_mode_t* videoMode,
void* opaque ) {
puts("Video mode changed");
}, &context);
puts("Video options changed");
}, &context);
context.sdk->SetFrameCallback([](
const asdk::frame_t* frame,
void* opaque ) {
#ifdef USE_STB_IMAGE_WRITE
#endif
}, &context);
context.sdk->SetEncodedStreamCallback([](
const asdk::StreamType type,
const void* data,
const uint32_t dataSize, void* opaque ) {
switch (type) {
break;
}
}, &context);
context.sdk->SetRoomPreviewImageCallback([](const uint32_t roomID, const uint64_t utc,
const uint8_t* data, const uint32_t size,
void* opaque ) {
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.roomJoinedState = RoomJoinedStateUndef;
break;
case StateConnect:
if (Connect(context)) context.state = StateConnecting;
else context.state = StateDisconnect;
break;
case StateConnecting:
context.state = StateRequestRooms;
puts("Server authenticated your connection");
}
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:
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);
printf(
"Audio codec(%d) at %d bits per second\n", audioOptions.
codec,
}
if (context.pendingFileHash != 0) {
const uint64_t hash = context.pendingFileHash;
context.pendingFileHash = 0;
if (context.sdk->RoomFileDownload(context.pendingFileRoomID,
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
CertificateState
Outcome of sdk_t::RequestCertificate.
AuthenticationResponse
Outcome of a login attempt, reported by AuthenticateResponseFunc.
ServerState
State of the connection to the server, reported by ServerStateFunc.
uint8_t UserCapabilityValue
@ AuthenticationResponseSuccess
@ ServerStateAuthenticateError
@ ServerStateConnectedAndAuthenticated
@ DeviceCapabilityBasic
Common baseline: H.265 video, Speex audio, microphone, WebP photo mode, ROI, chat and a display.
@ DeviceCapabilityFileTransfer
sdk_t * Initialize()
Loads the SDK shared library and creates an SDK handle.
RoomFileError
Room file transfer failure reason.
RoomFileDirection
Room file transfer direction.
Request
Request sent with sdk_t::SendRequest or sdk_t::SendRequestStr.
RoomResponse
Server answer to a Request, reported by RoomResponseFunc.
@ RequestRoomListSubscribe
ImageFormat
Encoding of the image delivered by RoomPreviewImageFunc.
StreamType
Kind of payload delivered by EncodedStreamFunc.
Decoded room audio, delivered by DecodedAudioFrameFunc.
uint32_t sampleCount
PCM samples in data.
uint32_t sampleRate
PCM sample rate, always AUDIO_SAMPLE_RATE.
Audio encoder settings, see sdk_t::SetAudioOptions and sdk_t::AudioOptions.
int32_t bitrate
Encoder target bitrate (bit/s).
AudioCodec codec
Encoder used by SendAudioFrame.
A server certificate, as filled in by sdk_t::RequestCertificate.
const char * data
Certificate data.
A decoded video or photo frame, delivered by FrameFunc.
int32_t height
Frame resolution height in pixels.
uint8_t * data
Frame RGB data (R8G8B8), width * height * 3 bytes.
int32_t width
Frame resolution width in pixels.
What the sending client is currently doing, delivered by VideoModeFunc.
Encoder settings in effect on the sending client, delivered by VideoOptionsFunc.