This commit is contained in:
Aria 2025-03-21 22:23:30 +11:00
commit 9c94d113d3
Signed by untrusted user who does not match committer: aria
GPG key ID: 19AB7AA462B8AB3B
10260 changed files with 1237388 additions and 0 deletions

View file

@ -0,0 +1,18 @@
INCLUDE_DIRECTORIES (
${STAR_CORE_INCLUDES}
${STAR_STREAMINGVIDEO_INCLUDES}
${STAR_STREAMINGVIDEO_INCLUDES}/twitch
)
SET (streamingvideo_HEADERS
StarStreamingVideoController.hpp
StarTwitchStreamingVideoController.hpp
)
SET (streamingvideo_SOURCES
StarStreamingVideoController.cpp
StarTwitchStreamingVideoController.cpp
)
ADD_LIBRARY (star_streamingvideo ${streamingvideo_SOURCES} ${streamingvideo_HEADERS})
TARGET_LINK_LIBRARIES (star_streamingvideo star)

View file

@ -0,0 +1,115 @@
#include "StarStreamingVideoController.hpp"
#include "StarTwitchStreamingVideoController.hpp"
namespace Star {
StreamingVideoController::StreamingVideoController() {
}
StreamingVideoController::~StreamingVideoController() {
}
void StreamingVideoController::setStreamConfiguration(Variant const& configuration) {
auto kind = configuration.getString("kind");
if (!m_impl || m_impl->kind() != kind) {
if (kind.equals("dummy", String::CaseInsensitive))
m_impl = {};
else if (kind.equals("twitch", String::CaseInsensitive))
m_impl = make_shared<TwitchStreamingVideoController>();
}
if (m_impl) {
m_impl->setFrameBufferSize(m_size);
m_impl->setStreamConfiguration(configuration);
}
}
bool StreamingVideoController::active() const {
if (m_impl)
return m_impl->active();
return false;
}
void StreamingVideoController::update() {
if (m_impl)
m_impl->update();
}
void StreamingVideoController::start() {
if (m_impl)
m_impl->start();
else
m_errors.append("Dummy video controller");
}
void StreamingVideoController::stop() {
if (m_impl)
m_impl->stop();
}
bool StreamingVideoController::hasError() {
if (m_impl)
return m_impl->hasError();
return m_errors.size() != 0;
}
String StreamingVideoController::nextError() {
if (m_impl)
return m_impl->nextError();
return m_errors.takeFirst();
}
bool StreamingVideoController::hasStatus() {
if (m_impl)
return m_impl->hasStatus();
return false;
}
String StreamingVideoController::nextStatus() {
if (m_impl)
return m_impl->nextStatus();
starAssert(false);
return "";
}
void StreamingVideoController::setFrameBufferSize(Vec2U const& size) {
if (m_impl)
m_impl->setFrameBufferSize(size);
m_size = size;
}
void StreamingVideoController::setStreamMetadata(Variant const& metadata) {
if (m_impl)
m_impl->setStreamMetadata(metadata);
}
bool StreamingVideoController::nextFrameExpected() {
if (m_impl)
return m_impl->nextFrameExpected();
return false;
}
StreamingVideoFrameBuffer StreamingVideoController::acquireFrameBuffer() {
if (m_impl)
return m_impl->acquireFrameBuffer();
starAssert(false);
return {};
}
void StreamingVideoController::submitFrameBuffer(StreamingVideoFrameBuffer buffer) {
if (m_impl)
m_impl->submitFrameBuffer(buffer);
else
starAssert(false);
}
String StreamingVideoController::kind() const {
if (m_impl)
return m_impl->kind();
return "dummy";
}
}

View file

@ -0,0 +1,54 @@
#ifndef STAR_STREAMING_VIDEO_CONTROLLER_HPP
#define STAR_STREAMING_VIDEO_CONTROLLER_HPP
#include "StarVariantExtra.hpp"
namespace Star {
struct StreamingVideoFrameBuffer {
StreamingVideoFrameBuffer() : width(), height(), buffer() {}
unsigned width;
unsigned height;
void* buffer;
};
class StreamingVideoController;
typedef shared_ptr<StreamingVideoController> StreamingVideoControllerPtr;
class StreamingVideoController {
public:
StreamingVideoController();
virtual ~StreamingVideoController();
virtual void setStreamConfiguration(Variant const& configuration);
virtual bool active() const;
virtual void update();
virtual void start();
virtual void stop();
virtual bool hasError();
virtual String nextError();
virtual bool hasStatus();
virtual String nextStatus();
virtual void setFrameBufferSize(Vec2U const& size);
virtual void setStreamMetadata(Variant const& metadata);
virtual bool nextFrameExpected();
virtual StreamingVideoFrameBuffer acquireFrameBuffer();
virtual void submitFrameBuffer(StreamingVideoFrameBuffer buffer);
protected:
virtual String kind() const;
private:
StreamingVideoControllerPtr m_impl;
List<String> m_errors;
Vec2U m_size;
};
}
#endif

View file

@ -0,0 +1,455 @@
#include "StarTwitchStreamingVideoController.hpp"
#include "twitchsdk.h"
#include "StarDynamicLib.hpp"
#include "StarFile.hpp"
namespace Star {
const char* twitchClientId = "cuxxi4cir240k3e95tfhdkjt1mtwe4f";
const char* twitchClientSecret = "8zdy461iyv1kiom0ejszqxq85djbqxr";
float const WorldTimestep = 1.0f / 60.0f;
enum class TwitchStreamingVideoControllerMode {
None, Initialize, WaitingForAuth, Authenticated, LoggingIn, LoggedIn, FindingIngestServer, FoundIngestServer, Start, Streaming, Cleanup
};
class TwitchStreamingVideoControllerInternals {
public:
DynamicLibPtr lib;
TTV_AuthToken authToken; // The unique key that allows the client to stream.
TTV_ChannelInfo channelInfo; // The information about the channel associated with the auth token
TTV_IngestList ingestList; // Will contain valid data the callback triggered due to TTV_GetIngestServers is called.
TTV_UserInfo userInfo; // Profile information about the local user.
TTV_StreamInfo streamInfo; // Information about the stream the user is streaming on.
TTV_IngestServer ingestServer; // The ingest server to use.
std::vector<unsigned char*> freeBufferList; // The list of free buffers. The app needs to allocate exactly 3.
std::vector<unsigned char*> captureBuffers; // The list of all buffers.
String username;
String password;
String clientSecret;
TwitchStreamingVideoControllerMode mode;
List<String> errors;
List<String> status;
Variant configuration;
Vec2U outputSize;
TTV_ErrorToString fTTV_ErrorToString;
TTV_Init fTTV_Init;
TTV_RequestAuthToken fTTV_RequestAuthToken;
TTV_Login fTTV_Login;
TTV_FreeIngestList fTTV_FreeIngestList;
TTV_GetIngestServers fTTV_GetIngestServers;
TTV_GetUserInfo fTTV_GetUserInfo;
TTV_GetStreamInfo fTTV_GetStreamInfo;
TTV_GetDefaultParams fTTV_GetDefaultParams;
TTV_Start fTTV_Start;
TTV_Stop fTTV_Stop;
TTV_Shutdown fTTV_Shutdown;
TTV_SubmitVideoFrame fTTV_SubmitVideoFrame;
TTV_PollTasks fTTV_PollTasks;
TTV_PollStats fTTV_PollStats;
TTV_SetTraceLevel fTTV_SetTraceLevel;
TTV_SetTraceOutput fTTV_SetTraceOutput;
};
shared_ptr<TwitchStreamingVideoControllerInternals> g_internals;
void AuthDoneCallback(TTV_ErrorCode result, void* userData) {
_unused(userData);
if ( TTV_SUCCEEDED(result)) {
g_internals->mode = TwitchStreamingVideoControllerMode::Authenticated;
} else {
const char* err = g_internals->fTTV_ErrorToString(result);
g_internals->errors.append(strf("AuthDoneCallback got failure: %s", err));
g_internals->mode = TwitchStreamingVideoControllerMode::Cleanup;
}
}
void LoginCallback(TTV_ErrorCode result, void* userData) {
_unused(userData);
if ( TTV_SUCCEEDED(result)) {
g_internals->mode = TwitchStreamingVideoControllerMode::LoggedIn;
} else {
const char* err = g_internals->fTTV_ErrorToString(result);
g_internals->errors.append(strf("LoginCallback got failure: %s", err));
g_internals->mode = TwitchStreamingVideoControllerMode::Cleanup;
}
}
void IngestListCallback(TTV_ErrorCode result, void* userData) {
_unused(userData);
if ( TTV_SUCCEEDED(result)) {
uint serverIndex = 0;
for (uint i = 0; i < g_internals->ingestList.ingestCount; ++i) {
// Use the default server for now
if (g_internals->ingestList.ingestList[i].defaultServer) {
serverIndex = i;
break;
}
}
g_internals->ingestServer = g_internals->ingestList.ingestList[serverIndex];
g_internals->mode = TwitchStreamingVideoControllerMode::FoundIngestServer;
} else {
const char* err = g_internals->fTTV_ErrorToString(result);
g_internals->errors.append(strf("IngestListCallback got failure: %s", err));
g_internals->mode = TwitchStreamingVideoControllerMode::Cleanup;
}
g_internals->fTTV_FreeIngestList(&g_internals->ingestList);
}
void UserInfoDoneCallback(TTV_ErrorCode result, void* /*userData*/) {
if ( TTV_FAILED(result)) {
const char* err = g_internals->fTTV_ErrorToString(result);
g_internals->errors.append(strf("UserInfoDoneCallback got failure: %s", err));
g_internals->mode = TwitchStreamingVideoControllerMode::Cleanup;
}
}
void StreamInfoDoneCallback(TTV_ErrorCode result, void* /*userData*/) {
if ( TTV_FAILED(result) && result != TTV_EC_WEBAPI_RESULT_NO_STREAMINFO) {
const char* err = g_internals->fTTV_ErrorToString(result);
g_internals->errors.append(strf("StreamInfoDoneCallback got failure: %s", err));
g_internals->mode = TwitchStreamingVideoControllerMode::Cleanup;
}
}
void FrameUnlockCallback(const uint8_t* buffer, void* /*userData*/) {
unsigned char* p = const_cast<unsigned char*>(buffer);
g_internals->freeBufferList.push_back(p);
}
TwitchStreamingVideoController::TwitchStreamingVideoController() {
m_internals = make_shared<TwitchStreamingVideoControllerInternals>();
g_internals = m_internals;
m_internals->mode = TwitchStreamingVideoControllerMode::None;
m_timer = 0;
#ifdef WIN32
m_internals->lib = DynamicLib::loadLibrary("twitchsdk.dll");
#endif
m_internals->fTTV_ErrorToString = (TTV_ErrorToString)m_internals->lib->funcPtr("TTV_ErrorToString");
m_internals->fTTV_Init = (TTV_Init)m_internals->lib->funcPtr("TTV_Init");
m_internals->fTTV_RequestAuthToken = (TTV_RequestAuthToken)m_internals->lib->funcPtr("TTV_RequestAuthToken");
m_internals->fTTV_Login = (TTV_Login)m_internals->lib->funcPtr("TTV_Login");
m_internals->fTTV_FreeIngestList = (TTV_FreeIngestList)m_internals->lib->funcPtr("TTV_FreeIngestList");
m_internals->fTTV_GetIngestServers = (TTV_GetIngestServers)m_internals->lib->funcPtr("TTV_GetIngestServers");
m_internals->fTTV_GetUserInfo = (TTV_GetUserInfo)m_internals->lib->funcPtr("TTV_GetUserInfo");
m_internals->fTTV_GetStreamInfo = (TTV_GetStreamInfo)m_internals->lib->funcPtr("TTV_GetStreamInfo");
m_internals->fTTV_GetDefaultParams = (TTV_GetDefaultParams)m_internals->lib->funcPtr("TTV_GetDefaultParams");
m_internals->fTTV_Start = (TTV_Start)m_internals->lib->funcPtr("TTV_Start");
m_internals->fTTV_Stop = (TTV_Stop)m_internals->lib->funcPtr("TTV_Stop");
m_internals->fTTV_Shutdown = (TTV_Shutdown)m_internals->lib->funcPtr("TTV_Shutdown");
m_internals->fTTV_SubmitVideoFrame = (TTV_SubmitVideoFrame)m_internals->lib->funcPtr("TTV_SubmitVideoFrame");
m_internals->fTTV_PollTasks = (TTV_PollTasks)m_internals->lib->funcPtr("TTV_PollTasks");
m_internals->fTTV_PollStats = (TTV_PollStats)m_internals->lib->funcPtr("TTV_PollStats");
m_internals->fTTV_SetTraceLevel = (TTV_SetTraceLevel)m_internals->lib->funcPtr("TTV_SetTraceLevel");
m_internals->fTTV_SetTraceOutput = (TTV_SetTraceOutput)m_internals->lib->funcPtr("TTV_SetTraceOutput");
}
TwitchStreamingVideoController::~TwitchStreamingVideoController() {}
void TwitchStreamingVideoController::setStreamConfiguration(Variant const& configuration) {
m_internals->configuration = configuration;
}
bool TwitchStreamingVideoController::active() const {
return (m_internals->mode != TwitchStreamingVideoControllerMode::None);
}
void TwitchStreamingVideoController::update() {
TTV_ErrorCode ret;
if ((m_internals->mode != TwitchStreamingVideoControllerMode::None) && (m_internals->mode !=TwitchStreamingVideoControllerMode::Initialize)) {
ret = m_internals->fTTV_PollTasks();
if (TTV_FAILED(ret)) {
const char* err = g_internals->fTTV_ErrorToString(ret);
m_internals->errors.append(strf("Error while polling tasks: %s", err));
// return;
}
ret = m_internals->fTTV_PollStats();
if (TTV_FAILED(ret)) {
const char* err = g_internals->fTTV_ErrorToString(ret);
m_internals->errors.append(strf("Error while polling stats: %s", err));
// return;
}
}
switch (m_internals->mode) {
case TwitchStreamingVideoControllerMode::None: {
break;
}
case TwitchStreamingVideoControllerMode::Initialize: {
String clientId = twitchClientId;
String caCertPath = File::fullPath(m_internals->configuration.getString("caCertPath"));
String dllLoadPath = File::fullPath(m_internals->configuration.getString("dllLoadPath"));
// Initialize the SDK
std::wstring caCertPathW = caCertPath.wstring();
std::wstring dllLoadPathW = dllLoadPath.wstring();
wchar_t* caCertPathWptr = (wchar_t*)caCertPathW.c_str();
wchar_t* dllLoadPathWptr = (wchar_t*)dllLoadPathW.c_str();
ret = g_internals->fTTV_Init(nullptr, clientId.utf8Ptr(), caCertPathWptr, TTV_VID_ENC_DEFAULT, dllLoadPathWptr);
if ( TTV_FAILED(ret)) {
const char* err = g_internals->fTTV_ErrorToString(ret);
m_internals->errors.append(strf("Error while initializing the Twitch SDK: %s", err));
m_internals->mode = TwitchStreamingVideoControllerMode::None;
return;
}
if (m_internals->configuration.getBool("tracing", false)) {
auto trace = File::fullPath(m_internals->configuration.getString("traceFile"));
std::wstring traceFileW = trace.wstring();
wchar_t* traceFileWPtr = (wchar_t*)traceFileW.c_str();
m_internals->fTTV_SetTraceOutput(traceFileWPtr);
m_internals->fTTV_SetTraceLevel(TTV_MessageLevel::TTV_ML_DEBUG);
}
m_internals->username = m_internals->configuration.getString("username");
m_internals->password = m_internals->configuration.getString("password");
m_internals->clientSecret = twitchClientSecret;
// Obtain the AuthToken which will allow the user to stream
TTV_AuthParams authParams;
authParams.size = sizeof(TTV_AuthParams);
authParams.userName = m_internals->username.utf8Ptr();
authParams.password = m_internals->password.utf8Ptr();
authParams.clientSecret = m_internals->clientSecret.utf8Ptr();
m_internals->mode = TwitchStreamingVideoControllerMode::WaitingForAuth;
ret = g_internals->fTTV_RequestAuthToken(&authParams, AuthDoneCallback, nullptr, &m_internals->authToken);
if ( TTV_FAILED(ret)) {
const char* err = g_internals->fTTV_ErrorToString(ret);
m_internals->errors.append(strf("Error while requesting auth token: %s", err));
m_internals->mode = TwitchStreamingVideoControllerMode::Cleanup;
return;
}
break;
}
case TwitchStreamingVideoControllerMode::WaitingForAuth: {
break;
}
case TwitchStreamingVideoControllerMode::Authenticated: {
m_internals->mode = TwitchStreamingVideoControllerMode::LoggingIn;
m_internals->channelInfo.size = sizeof(m_internals->channelInfo);
ret = g_internals->fTTV_Login(&m_internals->authToken, LoginCallback, nullptr, &m_internals->channelInfo);
if (TTV_FAILED(ret)) {
const char* err = g_internals->fTTV_ErrorToString(ret);
m_internals->errors.append(strf("Error while trying to login: %s", err));
m_internals->mode = TwitchStreamingVideoControllerMode::Cleanup;
return;
}
break;
}
case TwitchStreamingVideoControllerMode::LoggingIn: {
break;
}
case TwitchStreamingVideoControllerMode::LoggedIn: {
m_internals->mode = TwitchStreamingVideoControllerMode::FindingIngestServer;
ret = g_internals->fTTV_GetIngestServers(&m_internals->authToken, IngestListCallback, nullptr, &m_internals->ingestList);
if (TTV_FAILED(ret)) {
const char* err = g_internals->fTTV_ErrorToString(ret);
m_internals->errors.append(strf("Error while trying to fetch ingest servers: %s", err));
m_internals->mode = TwitchStreamingVideoControllerMode::Cleanup;
return;
}
break;
}
case TwitchStreamingVideoControllerMode::FindingIngestServer: {
break;
}
case TwitchStreamingVideoControllerMode::FoundIngestServer: {
m_internals->mode = TwitchStreamingVideoControllerMode::Start;
m_internals->userInfo.size = sizeof(m_internals->userInfo);
m_internals->streamInfo.size = sizeof(m_internals->streamInfo);
// Kick off requests for the user and stream information that aren't 100% essential to be ready before streaming starts
ret = g_internals->fTTV_GetUserInfo(&m_internals->authToken, UserInfoDoneCallback, nullptr, &m_internals->userInfo);
if (TTV_FAILED(ret)) {
const char* err = g_internals->fTTV_ErrorToString(ret);
m_internals->errors.append(strf("Error while trying to fetch user info: %s", err));
m_internals->mode = TwitchStreamingVideoControllerMode::Cleanup;
return;
}
ret = g_internals->fTTV_GetStreamInfo(&m_internals->authToken, StreamInfoDoneCallback, nullptr, m_internals->username.utf8Ptr(), &m_internals->streamInfo);
if (TTV_FAILED(ret)) {
const char* err = g_internals->fTTV_ErrorToString(ret);
m_internals->errors.append(strf("Error while trying to fetch stream info: %s", err));
m_internals->mode = TwitchStreamingVideoControllerMode::Cleanup;
return;
}
break;
}
case TwitchStreamingVideoControllerMode::Start: {
TTV_ErrorCode ret;
TTV_VideoParams videoParams;
memset(&videoParams, 0, sizeof(TTV_VideoParams));
videoParams.size = sizeof(TTV_VideoParams);
videoParams.outputWidth = m_internals->outputSize[0];
videoParams.outputHeight = m_internals->outputSize[1];
videoParams.targetFps = m_internals->configuration.getUInt("targetFps");
videoParams.verticalFlip = m_internals->configuration.getBool("verticalFlip");
// Compute the rest of the fields based on the given parameters
ret = g_internals->fTTV_GetDefaultParams(&videoParams);
if ( TTV_FAILED(ret)) {
const char* err = g_internals->fTTV_ErrorToString(ret);
m_internals->errors.append(strf("Error while preparing to start the stream: %s", err));
m_internals->mode = TwitchStreamingVideoControllerMode::Cleanup;
return;
}
videoParams.pixelFormat = TTV_PF_BGRA;
// Setup the audio parameters
TTV_AudioParams audioParams;
memset(&audioParams, 0, sizeof(TTV_AudioParams));
audioParams.size = sizeof(TTV_AudioParams);
audioParams.audioEnabled = m_internals->configuration.getBool("audioEnabled");
ret = g_internals->fTTV_Start(&videoParams, &audioParams, &m_internals->ingestServer, 0, nullptr, nullptr);
if ( TTV_FAILED(ret)) {
const char* err = g_internals->fTTV_ErrorToString(ret);
m_internals->errors.append(strf("Error while starting to stream: %s", err));
m_internals->mode = TwitchStreamingVideoControllerMode::Cleanup;
return;
}
m_internals->mode = TwitchStreamingVideoControllerMode::Streaming;
// Allocate exactly 3 buffers to use as the capture destination while streaming.
// These buffers are passed to the SDK.
for (unsigned int i = 0; i < 3; ++i) {
unsigned char* pBuffer = new unsigned char[videoParams.outputWidth * videoParams.outputHeight * 4];
m_internals->captureBuffers.push_back(pBuffer);
m_internals->freeBufferList.push_back(pBuffer);
}
break;
}
case TwitchStreamingVideoControllerMode::Streaming: {
m_timer -= WorldTimestep;
if (m_timer < 0) {
ret = g_internals->fTTV_GetStreamInfo(&m_internals->authToken, StreamInfoDoneCallback, nullptr, m_internals->username.utf8Ptr(), &m_internals->streamInfo);
if (TTV_FAILED(ret)) {
const char* err = g_internals->fTTV_ErrorToString(ret);
m_internals->errors.append(strf("Error while trying to fetch stream info on timer: %s", err));
m_internals->mode = TwitchStreamingVideoControllerMode::Cleanup;
return;
}
m_timer = m_internals->configuration.getFloat("refreshTimer");
}
break;
}
case TwitchStreamingVideoControllerMode::Cleanup: {
m_internals->mode = TwitchStreamingVideoControllerMode::None;
TTV_ErrorCode ret = g_internals->fTTV_Stop(nullptr, nullptr);
if ( TTV_FAILED(ret)) {
const char* err = g_internals->fTTV_ErrorToString(ret);
m_internals->errors.append(strf("Error while stopping the stream: %s", err));
}
// Delete the capture buffers
for (unsigned int i = 0; i < m_internals->captureBuffers.size(); ++i) {
delete[] m_internals->captureBuffers[i];
}
m_internals->freeBufferList.clear();
m_internals->captureBuffers.clear();
ret = g_internals->fTTV_Shutdown();
if ( TTV_FAILED(ret)) {
const char* err = g_internals->fTTV_ErrorToString(ret);
m_internals->errors.append(strf("Error while shutting down the Twitch SDK: %s", err));
return;
}
break;
}
}
}
void TwitchStreamingVideoController::start() {
if (m_internals->mode != TwitchStreamingVideoControllerMode::None) {
m_internals->errors.append("Already started.");
}
else {
m_internals->mode = TwitchStreamingVideoControllerMode::Initialize;
}
}
void TwitchStreamingVideoController::stop() {
if (active())
m_internals->mode = TwitchStreamingVideoControllerMode::Cleanup;
}
bool TwitchStreamingVideoController::hasError() {
return m_internals->errors.size() != 0;
}
String TwitchStreamingVideoController::nextError() {
return m_internals->errors.takeFirst();
}
bool TwitchStreamingVideoController::hasStatus() {
return m_internals->status.size() != 0;
}
String TwitchStreamingVideoController::nextStatus() {
return m_internals->status.takeFirst();
}
void TwitchStreamingVideoController::setFrameBufferSize(Vec2U const& size) {
auto outputSize = Vec2U((size[0] /32) *32, (size[1] /32) *32);
if (m_internals->outputSize != outputSize) {
m_internals->outputSize = outputSize;
if (active())
stop();
}
}
void TwitchStreamingVideoController::setStreamMetadata(Variant const& metadata) {
_unused(metadata);
}
bool TwitchStreamingVideoController::nextFrameExpected() {
return m_internals->freeBufferList.size() != 0;
}
StreamingVideoFrameBuffer TwitchStreamingVideoController::acquireFrameBuffer() {
StreamingVideoFrameBuffer result;
result.width = m_internals->outputSize[0];
result.height = m_internals->outputSize[1];
result.buffer = m_internals->freeBufferList.back();
m_internals->freeBufferList.pop_back();
return result;
}
void TwitchStreamingVideoController::submitFrameBuffer(StreamingVideoFrameBuffer buffer) {
TTV_ErrorCode ret = g_internals->fTTV_SubmitVideoFrame((uint8_t*)buffer.buffer, FrameUnlockCallback, 0);
if ( TTV_FAILED(ret)) {
m_internals->mode = TwitchStreamingVideoControllerMode::Cleanup;
const char* err = g_internals->fTTV_ErrorToString(ret);
m_internals->errors.append(strf("Error while submitting frame to stream: %s", err));
}
}
String TwitchStreamingVideoController::kind() const {
return "twitch";
}
}

View file

@ -0,0 +1,45 @@
#ifndef STAR_TWITCH_STREAMING_VIDEO_CONTROLLER_HPP
#define STAR_TWITCH_STREAMING_VIDEO_CONTROLLER_HPP
#include "StarStreamingVideoController.hpp"
namespace Star {
class TwitchStreamingVideoControllerInternals;
class TwitchStreamingVideoController: public StreamingVideoController {
public:
TwitchStreamingVideoController();
virtual ~TwitchStreamingVideoController();
virtual void setStreamConfiguration(Variant const& configuration) override;
virtual bool active() const override;
virtual void update() override;
virtual void start() override;
virtual void stop() override;
virtual bool hasError() override;
virtual String nextError() override;
virtual bool hasStatus() override;
virtual String nextStatus() override;
virtual void setFrameBufferSize(Vec2U const& size) override;
virtual void setStreamMetadata(Variant const& metadata) override;
virtual bool nextFrameExpected() override;
virtual StreamingVideoFrameBuffer acquireFrameBuffer() override;
virtual void submitFrameBuffer(StreamingVideoFrameBuffer buffer) override;
protected:
virtual String kind() const override;
private:
float m_timer;
shared_ptr<TwitchStreamingVideoControllerInternals> m_internals;
};
}
#endif

View file

@ -0,0 +1,488 @@
/********************************************************************************************
* Twitch Broadcasting SDK
*
* This software is supplied under the terms of a license agreement with Justin.tv Inc. and
* may not be copied or used except in accordance with the terms of that agreement
* Copyright (c) 2012-2013 Justin.tv Inc.
*********************************************************************************************/
#ifndef TTVSDK_TWITCH_CHAT_H
#define TTVSDK_TWITCH_CHAT_H
#include "twitchsdktypes.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* TTV_ChatEvent - The various events coming from the chat system.
*/
typedef enum
{
TTV_CHAT_JOINED_CHANNEL, //!< Local user joined a channel.
TTV_CHAT_LEFT_CHANNEL //!< Local user left a channel.
} TTV_ChatEvent;
/**
* TTV_ChatUserMode - A list of the mode flags a user may have.
*/
typedef enum
{
TTV_CHAT_USERMODE_VIEWER = 0, //!< A regulare viewer.
TTV_CHAT_USERMODE_MODERATOR = 1 << 0, //!< A moderator.
TTV_CHAT_USERMODE_BROADCASTER = 1 << 1, //!< The broadcaster.
TTV_CHAT_USERMODE_ADMINSTRATOR = 1 << 2, //!< An admin.
TTV_CHAT_USERMODE_STAFF = 1 << 3, //!< A member of Twitch.
TTV_CHAT_USERMODE_BANNED = 1 << 30 //!< The user has been banned. This flag may not always be up to date.
} TTV_ChatUserMode;
/**
* TTV_ChatUserSubscription - A list of the subscription flags a user may have.
*/
typedef enum
{
TTV_CHAT_USERSUB_NONE = 0, //!< A standard user.
TTV_CHAT_USERSUB_SUBSCRIBER = 1 << 0, //!< A subscriber in the current channel.
TTV_CHAT_USERSUB_TURBO = 1 << 1 //!< A Twitch Turbo account.
} TTV_ChatUserSubscription;
/**
* This is the maximum length of the user name in bytes, NOT characters. Be careful with multi-byte characters in UTF-8.
* However, user names are currently restricted to ASCII which is confined to the lower 7 bits so the encodings are the same.
*/
#define kMaxChatUserNameLength 63
/**
* TTV_ChatUserInfo - The user information.
*/
typedef struct
{
utf8char displayName[kMaxChatUserNameLength+1]; //!< The UTF-8 encoded displayed name. Currently restricted to the ASCII subset.
TTV_ChatUserMode modes; //!< The mode which controls priviledges in a particular chat room.
TTV_ChatUserSubscription subscriptions; //!< The user's subscriptions for the channel.
unsigned int nameColorARGB; //!< The current ARGB color of the user's name text.
unsigned int emoticonSet; //!< The emoticon set id for the user.
bool ignore; //!< Whether or not to ignore the user.
} TTV_ChatUserInfo;
/**
* TTV_ChatUserList - A list of chat users.
*/
typedef struct
{
TTV_ChatUserInfo* userList; //!< The array of user info entries.
unsigned int userCount; //!< The number of entries in the array.
} TTV_ChatUserList;
/**
* This is the maximum length of the channel name in bytes, NOT characters. Be careful with multi-byte characters in UTF-8.
* However, user names are currently restricted to ASCII which is confined to the lower 7 bits so the encodings happen to be the same (for now).
*/
#define kMaxChatChannelNameLength 63
/**
* TTV_ChatChannelInfo - Information about a chat channel.
*/
typedef struct
{
utf8char name[kMaxChatChannelNameLength+1]; //!< The UTF-8 encoded name of the channel. Currently restricted to the ASCII subset.
TTV_ChatUserInfo broadcasterUserInfo; //!< Information about the broadcaster of the stream.
} TTV_ChatChannelInfo;
/**
* This is the maximum length of the message in bytes, NOT characters. Be careful with multi-byte characters in UTF-8.
*/
#define kMaxChatMessageLength 510
/**
* TTV_ChatMessage - A message from a user in a chat channel.
*/
typedef struct
{
utf8char userName[kMaxChatUserNameLength+1]; //!< The UTF-8 encoded user that sent the message. Currently restricted to the ASCII subset.
utf8char message[kMaxChatMessageLength+1]; //!< The UTF-8 encoded message text.
TTV_ChatUserMode modes; //!< The mode which controls priviledges in a particular chat room.
TTV_ChatUserSubscription subscriptions; //!< The user's subscriptions for the channel.
unsigned int nameColorARGB; //!< The ARGB color of the name text.
unsigned int emoticonSet; //!< The emoticon set to use when rendering emoticons. 0 is the default.
bool action; //!< Whether or not the message is an action. If true, it should be displayed entirely in the name text color and of the form "<userName> <message>".
} TTV_ChatMessage;
/**
* TTV_ChatMessageList - A list of chat messages.
*/
typedef struct
{
TTV_ChatMessage* messageList; //!< The ordered array of chat messages.
unsigned int messageCount; //!< The number of messages in the list.
} TTV_ChatMessageList;
/**
* TTV_ChatMessageTokenType - The types of tokens that can be generated from a chat message.
*/
typedef enum
{
TTV_CHAT_MSGTOKEN_TEXT,
TTV_CHAT_MSGTOKEN_IMAGE
} TTV_ChatMessageTokenType;
/**
* TTV_ChatTextMessageToken - Information about a text token.
*/
typedef struct
{
utf8char buffer[kMaxChatMessageLength];
} TTV_ChatTextMessageToken;
/**
* TTV_ChatImageMessageToken - Information about an image token.
*/
typedef struct
{
int sheetIndex; //!< The index of the sheet to use when rendering. -1 means no image.
unsigned short x1; //!< The left edge in pixels on the sheet.
unsigned short y1; //!< The top edge in pixels on the sheet.
unsigned short x2; //!< The right edge in pixels on the sheet.
unsigned short y2; //!< The bottom edge in pixels on the sheet.
} TTV_ChatImageMessageToken;
/**
* TTV_ChatMessageToken - Information about an image token.
*/
typedef struct
{
TTV_ChatMessageTokenType type; //!< The way to interpret the data.
union
{
TTV_ChatTextMessageToken text;
TTV_ChatImageMessageToken image;
} data;
} TTV_ChatMessageToken;
/**
* TTV_ChatTokenizedMessage - A list of tokens parsed from a text message.
*/
typedef struct
{
utf8char displayName[kMaxChatUserNameLength+1]; //!< The UTF-8 encoded displayed name. Currently restricted to the ASCII subset.
TTV_ChatUserMode modes; //!< The modes of the user who sent the message.
TTV_ChatUserSubscription subscriptions; //!< The subscriptions of the user who sent the message.
unsigned int nameColorARGB; //!< The current ARGB color of the user's name text.
TTV_ChatMessageToken* tokenList; //!< The array of message tokens.
unsigned int tokenCount; //!< The number of entries in tokenList.
} TTV_ChatTokenizedMessage;
/**
* TTV_ChatSpriteSheet - The texture data which can be loaded into a texture and used for rendering emoticons and badges.
*/
typedef struct
{
unsigned int sheetIndex; //!< The index of the sprite sheet.
const uint8_t* buffer; //!< The RGBA buffer data, 8 bits per channel.
unsigned int width; //!< The width of the buffer in pixels.
unsigned int height; //!< The height of the buffer in pixels.
} TTV_ChatTextureSheet;
/**
* TTV_ChatTextureSheetList - A list of texture sheets.
*/
typedef struct
{
TTV_ChatTextureSheet* list; //!< The array of sheets.
unsigned int count; //!< The number of entries in the array.
} TTV_ChatTextureSheetList;
/**
* TTV_ChatBadgeData - Information about how to render badges based on the subscriptions and user modes.
*/
typedef struct
{
TTV_ChatImageMessageToken turboIcon;
TTV_ChatImageMessageToken channelSubscriberIcon;
TTV_ChatImageMessageToken broadcasterIcon;
TTV_ChatImageMessageToken staffIcon;
TTV_ChatImageMessageToken adminIcon;
TTV_ChatImageMessageToken moderatorIcon;
} TTV_ChatBadgeData;
/**
* TTV_ChatEmoticonData - Information to use when rendering emoticons and badges.
*/
typedef struct
{
utf8char channel[kMaxChatChannelNameLength+1];
TTV_ChatTextureSheetList textures;
TTV_ChatBadgeData badges;
} TTV_ChatEmoticonData;
/**
* Callback signature for connection and disconnection events from the chat service. Once a connecion is successful, this may be
* called at any time to indicate a disconnect from the server. If a disconnection occurs, TTV_ChatConnect must be called again
* to connect to the server and all channels must be rejoined.
*
* When a connection is attempted via TTV_ChatConnect, a successful connection will result in the callback being called with TTV_EC_SUCCESS.
* Otherwise, an error will be returned which can be one of TTV_EC_CHAT_INVALID_LOGIN, TTV_EC_CHAT_LOST_CONNECTION, TTV_EC_CHAT_COULD_NOT_CONNECT.
*/
typedef void (*TTV_ChatStatusCallback) (TTV_ErrorCode result);
/**
* Callback signature for result of the local user joining or leaving channels.
*
* Expected evt values are TTV_CHAT_JOINED_CHANNEL, TTV_CHAT_LEFT_CHANNEL.
*/
typedef void (*TTV_ChatChannelMembershipCallback) (TTV_ChatEvent evt, const TTV_ChatChannelInfo* channelInfo);
/**
* Callback signature for notifications of users joining, leaving or changing their attributes in a chat channel. The lists returned in this callback must be freed by
* calling TTV_Chat_FreeUserList on each one when the application is done with them.
*/
typedef void (*TTV_ChatChannelUserChangeCallback) (const TTV_ChatUserList* joinList, const TTV_ChatUserList* leaveList, const TTV_ChatUserList* infoChangeList);
/**
* Callback signature for a reply to TTV_ChatGetChannelUsers for a request for the user list for a chat channel. The list returned in the callback must be freed by
* calling TTV_Chat_FreeUserList when the application is done with it or it will leak each time the callback is called.
*/
typedef void (*TTV_ChatQueryChannelUsersCallback) (const TTV_ChatUserList* userList);
/**
* Callback signature for notifications of a message event occurring in chat. This list is freed automatically when the call to the callback returns
* so be sure not to retain a reference to the list.
*/
typedef void (*TTV_ChatChannelMessageCallback) (const TTV_ChatMessageList* messageList);
/**
* Callback signature for notifications that the chatroom should be cleared.
*/
typedef void (*TTV_ChatClearCallback) (const utf8char* channelName);
/**
* Callback to indicate the result of the request to fetch emoticon data.
*
* @param error Specifies any error or warning that may have occurred while preparing the emoticon data.
*/
typedef void (*TTV_EmoticonDataDownloadCallback) (TTV_ErrorCode error);
/**
* TTV_ChatCallbacks - The set of callbacks to call for notifications from the chat subsystem.
*/
typedef struct
{
TTV_ChatStatusCallback statusCallback; //!< The callback to call for connection and disconnection events from the chat service. Cannot be NULL.
TTV_ChatChannelMembershipCallback membershipCallback; //!< The callback to call when the local user joins or leaves a channel. Cannot be NULL.
TTV_ChatChannelUserChangeCallback userCallback; //!< The callback to call when other users join or leave a channel. This may be NULL.
TTV_ChatChannelMessageCallback messageCallback; //!< The callback to call when a message is received on a channel. Cannot be NULL.
TTV_ChatClearCallback clearCallback; //!< The callback to call when the chatroom should be cleared. Can be NULL.
} TTV_ChatCallbacks;
/**
* TTV_ChatInit - Sets the callbacks for receiving chat events. This may be NULL to stop receiving chat events but this is not recommended
* since you may miss connection and disconnection events.
*
* @param[in] channelName - The UTF-8 encoded name of the channel to connect to. See #kMaxChatChannelNameLength for details.
* @param[in] caCertFile - Full path of the CA Cert bundle file (Strongly encourage using the bundle file provided with the SDK).
* @param[in] chatCallbacks - The set of callbacks for receiving chat events.
* @return - TTV_EC_SUCCESS.
*/
TTVSDK_API TTV_ErrorCode TTV_Chat_Init(const utf8char* channelName, const wchar_t* caCertFile, const TTV_ChatCallbacks* chatCallbacks);
/**
* TTV_Chat_Shutdown - Tear down the chat subsystem. Be sure to have freed all outstanding lists before calling this.
*
* @return - TTV_EC_SUCCESS.
*/
TTVSDK_API TTV_ErrorCode TTV_Chat_Shutdown();
/**
* TTV_ChatConnect - Connects to the chat service. This is an asynchronous call and notification of
* connection success or fail will come in the callback. TTV_Chat_Init should be called first with
* valid callbacks for receiving connection and disconnection events. The actual result of the connection attempt will
* come in the statusCallback.
*
* @param[in] username - The UTF-8 encoded account username to use for logging in to chat. See #kMaxChatUserNameLength for details.
* @param[in] authToken - The auth token for the account.
* @return - TTV_EC_SUCCESS if the request to connect is valid (does not guarantee connection, wait for a response from statusCallback).
* TTV_EC_CHAT_NOT_INITIALIZED if system not initialized.
* TTV_EC_CHAT_ALREADY_IN_CHANNEL if already in channel.
* TTV_EC_CHAT_LEAVING_CHANNEL if still leaving a channel.
*/
TTVSDK_API TTV_ErrorCode TTV_Chat_Connect(const utf8char* username, const TTV_AuthToken* authToken);
/**
* TTV_Chat_ConnectAnonymous - Connects to the chat service anonymously allowing chat messages to be received but not sent. This is an asynchronous
* call and notification of connection success or fail will come in the callback. TTV_Chat_Init should be called first with
* valid callbacks for receiving connection and disconnection events. The actual result of the connection attempt will
* come in the statusCallback.
*
* @return - TTV_EC_SUCCESS if the request to connect is valid (does not guarantee connection, wait for a response from statusCallback).
* TTV_EC_CHAT_NOT_INITIALIZED if system not initialized.
* TTV_EC_CHAT_ALREADY_IN_CHANNEL if already in channel.
* TTV_EC_CHAT_LEAVING_CHANNEL if still leaving a channel.
*/
TTVSDK_API TTV_ErrorCode TTV_Chat_ConnectAnonymous();
/**
* TTV_ChatDisconnect - Disconnects from the chat server. This will automatically remove the user from
* all channels that the user is in. A notification will come in statusCallback to indicate
* that the disconnection was successful but you can safely assume this will succeed.
*
* @return - TTV_EC_SUCCESS if disconnection successful.
* TTV_EC_CHAT_NOT_INITIALIZED if system not initialized.
*/
TTVSDK_API TTV_ErrorCode TTV_Chat_Disconnect();
/**
* TTV_ChatGetChannelUsers - Retrieves the current users for the named channel. This is used by both broadcasters and viewers.
* The list returned in the callback must be freed by calling TTV_Chat_FreeUserList when the application is done with it.
*
* @param[in] callback - The callback to call with the result of the query.
* @return - TTV_EC_SUCCESS if function succeeds.
* TTV_EC_CHAT_NOT_IN_CHANNEL if not in the channel.
* TTV_EC_CHAT_NOT_INITIALIZED if system not initialized.
*/
TTVSDK_API TTV_ErrorCode TTV_Chat_GetChannelUsers(TTV_ChatQueryChannelUsersCallback callback);
/**
* TTV_Chat_SendMessage - Sends the given message to the channel. The user must have joined the channel first.
* This is used by both broadcasters and viewers.
*
* The game/user may also send some commands using a message to take some action in the channel. The valid commands are:
*
* "/disconnect": Disconnects from the chat channel.
* "/commercial": Make all viewers who normally watch commercials see a commercial right now.
* "/mods": Get a list of all of the moderators in the current channel.
* "/mod <username>": Grant moderator status to the given user.
* "/unmod <username>": Revoke moderator status from the given user.
* "/ban: <username>": Ban the given user from your channel.
* "/unban <username>": Lift a ban or a time-out that has been given to the given user.
* "/clear": Clear the current chat history. This clears the chat room for all viewers.
* "/timeout <username>": Give a time-out to the given user.
* "/subscribers": Turn on subscribers-only mode, which keeps people who have not purchased channel subscriptions to this channel from talking in chat.
* "/subscribersoff": Turn off subscribers-only mode.
* "/slow <interval>": Require that chatters wait <interval> seconds between lines of chat.
* "/slowoff": Don't require that chatters wait between lines of chat anymore.
* "/fastsubs <on|off>": Makes subscribers exempt from /slow.
* "/me": Speak in the third person. Ex: /me want smash -> <my_username> want smash. The entire message should also be colored with the user color.
* "/color": Change the color of your username.
* "/ignore <username>": Ignores the named user.
* "/unignore <username>": Unignores the named user.
*
* @param[in] message - The UTF-8 encoded message to send to the channel.
* @return - TTV_EC_SUCCESS if function succeeds.
* TTV_EC_CHAT_NOT_INITIALIZED if system not initialized.
* TTV_EC_CHAT_ANON_DENIED if connected anonymously.
*/
TTVSDK_API TTV_ErrorCode TTV_Chat_SendMessage(const utf8char* message);
/**
* TTV_ChatFlushEvents - Calls callbacks for all events which has accumulated since the last flush. This include connects, disconnects,
* user changes and received messages.
*
* @return - TTV_EC_SUCCESS if function succeeds.
* TTV_EC_CHAT_NOT_INITIALIZED if system not initialized.
*/
TTVSDK_API TTV_ErrorCode TTV_Chat_FlushEvents();
/**
* TTV_Chat_FreeUserList - Frees the memory for the given user list which was passed to the application during a callback.
*
* @param[in] userList - The user list to free.
* @return - TTV_EC_SUCCESS if function succeeds.
*/
TTVSDK_API TTV_ErrorCode TTV_Chat_FreeUserList(const TTV_ChatUserList* userList);
/**
* TTV_Chat_TokenizeMessage - Takes a raw text message, parses it and breaks it into tokens which makes it easier to render messages with embedded emoticons.
* Badges for the sending user can be rendered using TTV_ChatBadgeData obtained from a call to TTV_Chat_GetBadgeData.
*
* @param[in] message - The message to tokenize.
* @param[out] tokenizedMessage - The data for the tokenized message. This must be freed by calling TTV_Chat_FreeTokenizeMessage.
* @return - TTV_EC_SUCCESS if function succeeds, TTV_EC_INVALID_ARG if the message is not valid.
*/
TTVSDK_API TTV_ErrorCode TTV_Chat_TokenizeMessage(const TTV_ChatMessage* message, TTV_ChatTokenizedMessage** tokenizedMessage);
/**
* TTV_Chat_FreeTokenizedMessage - Frees the memory allocated during a call to TTV_Chat_TokenizeMessage.
*
* @param[in] tokenizedMessage - The data to free.
* @return - TTV_EC_SUCCESS if function succeeds, TTV_EC_INVALID_ARG if the message is not expected.
*/
TTVSDK_API TTV_ErrorCode TTV_Chat_FreeTokenizedMessage(TTV_ChatTokenizedMessage* tokenizedMessage);
/**
* TTV_Chat_DownloadEmoticonData - Initiates a download of the emoticon data. This will trigger a redownload if called a second time. The callback will be called
* to indicate the success of the download. Call TTV_Chat_GetEmoticonDatato retrieve the data after it has
* been downloaded.
*
* @param[in] callback - The callback to call when the emoticon data has finished downloading and is prepared for use.
* @return - TTV_EC_SUCCESS if function succeeds
* TTV_EC_CHAT_EMOTICON_DATA_DOWNLOADING if the data is still downloading.
* TTV_EC_CHAT_EMOTICON_DATA_LOCKED if the data has been locked by a call to TTV_Chat_GetEmoticonData and has not yet been freed by TTV_Chat_FreeEmoticonData.
* TTV_EC_INVALID_ARG if an invalid callback.
*/
TTVSDK_API TTV_ErrorCode TTV_Chat_DownloadEmoticonData(TTV_EmoticonDataDownloadCallback callback);
/**
* TTV_Chat_GetEmoticonData - Retrieves the texture information and badge info after it has been downloaded and prepared. When done with this data be sure
* to call TTV_Chat_FreeEmoticonData to free the memory. Initiate the download by calling TTV_Chat_DownloadEmoticonData.
*
* @param[out] textureSheetList - The texture information that will be returned.
* @return - TTV_EC_SUCCESS if function succeeds.
* TTV_EC_CHAT_EMOTICON_DATA_DOWNLOADING if the data is still downloading.
* TTV_EC_CHAT_EMOTICON_DATA_NOT_READY if the data is not yet ready to be retrieved.
*/
TTVSDK_API TTV_ErrorCode TTV_Chat_GetEmoticonData(TTV_ChatEmoticonData** data);
/**
* TTV_Chat_FreeEmoticonData - Frees the data previously obtained from TTV_Chat_GetEmoticonData.
*
* @param[in] textureSheetList - The texture information that will be returned.
* @return - TTV_EC_SUCCESS if function succeeds.
* TTV_EC_INVALID_ARG if not a previously retrieved list.
*/
TTVSDK_API TTV_ErrorCode TTV_Chat_FreeEmoticonData(TTV_ChatEmoticonData* data);
#ifdef __cplusplus
}
#endif
#endif /* TTVSDK_TWITCH_CHAT_H */

View file

@ -0,0 +1,384 @@
/*
*
* Bartwe: 20130617 - Changed interface to export stdcall function pointers
*
*/
/********************************************************************************************
* Twitch Broadcasting SDK
*
* This software is supplied under the terms of a license agreement with Justin.tv Inc. and
* may not be copied or used except in accordance with the terms of that agreement
* Copyright (c) 2012-2013 Justin.tv Inc.
*********************************************************************************************/
#ifndef TTVSDK_TWITCH_SDK_H
#define TTVSDK_TWITCH_SDK_H
#include "twitchsdktypes.h"
#ifdef __cplusplus
extern "C"
{
#endif
#ifndef TTV_CALLSPEC
#define TTV_CALLSPEC
#endif
/**
* TTV_Init - Initialize the Twitch Broadcasting SDK
*
* @param[in] memCallbacks - Memory allocation/deallocation callback functions provided by the client. If nullptr, malloc/free will be used
* @param[in] clientID - The Twitch client ID assigned to your application
* @param[in] caCertFile - Full path of the CA Cert bundle file (Strongly encourage using the bundle file provided with the SDK)
* @param[in] vidEncoder - The video encoder to use
* @param[in] audioEncoder - The audio encoder to use
* @param[in] dllPath - [Optional] Windows Only - Path to DLL's to load if no in exe folder (e.g. Intel DLL)
* @return - TTV_EC_SUCCESS if function succeeds; error code otherwise
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_Init)(const TTV_MemCallbacks* memCallbacks,
const char* clientID,
const wchar_t* caCertFile,
TTV_VideoEncoder vidEncoder,
const wchar_t* dllPath);
/**
* TTV_GetDefaultParams - Fill in the video parameters with default settings based on supplied resolution and target FPS
* This function is now deprecated. You should use TTV_GetMaxResolution to work backwards from the bitrate.
* @param[in,out] vidParams - The video params to be filled in with default settings
* NOTE: The width, height and targetFps members of the vidParams MUST be set by the caller
* @return - TTV_EC_SUCCESS if function succeeds; error code otherwise
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_GetDefaultParams)(TTV_VideoParams* vidParams);
/**
* TTV_GetMaxResolution - Using the provided maximum bitrate, motion factor, and aspect ratio, calculate
* the maximum resolution at which the video quality would be acceptable.
*
* @param[in] maxKbps - Maximum bitrate supported (this should be determined by running the ingest tester for a given ingest server)
* @param[in] frameRate - The desired frame rate. For a given bitrate and motion factor, a higher framerate will mean a lower resolution.
* @param[in] bitsPerPixel - The bits per pixel used in the final encoded video. A fast motion game (e.g. first person
shooter) required more bits per pixel of encoded video avoid compression artifacting. Use 0.1 for an
average motion game. For games without too many fast changes in the scene, you could use a value below
0.1 but not much. For fast moving games with lots of scene changes a value as high as 0.2 would be appropriate.
* @param[in] aspectRatio - The aspect ratio of the video which we'll use for calculating width and height
* @param[out] width - Maximum recommended width
* @param[out] height - Maximum recommended height
* @return - TTV_EC_SUCCESS if function succeeds; error code otherwise
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_GetMaxResolution)(uint maxKbps,
uint frameRate,
float bitsPerPixel,
float aspectRatio,
uint* width,
uint* height);
/**
* TTV_PollTasks - Polls all currently executing async tasks and if they've finished calls their callbacks
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_PollTasks)();
/**
* TTV_RequestAuthToken - Request an authentication key based on the provided username and password.
* @param[in] authParams - Authentication parameters
* @param[in] callback - The callback function to be called when the request is completed
* @param[in] userData - Optional pointer to be passed through to the callback function
* @param[out] authToken - The authentication token to be written to
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_RequestAuthToken)(const TTV_AuthParams* authParams,
TTV_TaskCallback callback,
void* userData,
TTV_AuthToken* authToken);
/**
* TTV_Login - Use the given auth token to log into the associated channel. This MUST be called
* before starting to stream and returns information about the channel. If the callback is called
* with a failure error code, the most likely cause is an invalid auth token and you need
* to call TTV_RequestAuthToken to obtain a new one.
* @param[in] authToken - The auth token to validate
* @param[in] callback - The callback function to be called when the request is completed
* @param[in] userData - Optional pointer to be passed through to the callback function
* @param[out] channelInfo (Optional; pass nullptr if not needed) - The channel info struct for the channel logged into
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_Login)(const TTV_AuthToken* authToken,
TTV_TaskCallback callback,
void* userData,
TTV_ChannelInfo* channelInfo);
/**
* TTV_GetIngestServers - Get the list of available ingest servers
* @param[in] authToken - The authentication token previously obtained
* @param[in] callback - The callback function to be called when function is completed
* @param[in] userData - Optional pointer to be passed through to the callback function
* @param[out] ingestList - The list of available ingest servers to choose from
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_GetIngestServers)(const TTV_AuthToken* authToken,
TTV_TaskCallback callback,
void* userData,
TTV_IngestList* ingestList);
/**
* TTV_FreeIngestList - Must be called after getting the ingest servers to free the allocated list of server info
* @param[in] ingestList - Pointer to the TTV_IngestList struct to be freed
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_FreeIngestList)(TTV_IngestList* ingestList);
/**
* TTV_Start - Starts streaming. This function is asynchronous if a valid callback is provided.
* @param[in] videoParams - Output stream video paramaters
* @param[in] audioParams - Output stream audio parameters
* @param[in] ingestServer - The ingest server to use
* @param[in] flags - optional flags
* @param[in] callback - The callback to call when the operation has completed. Can be null to force this function to be synchronous.
* @param[in] userData - Client data to pass along in the callback.
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_Start)(const TTV_VideoParams* videoParams,
const TTV_AudioParams* audioParams,
const TTV_IngestServer* ingestServer,
uint32_t flags,
TTV_TaskCallback callback,
void* userData);
/**
* TTV_SubmitVideoFrame - Submit a video frame to be added to the video stream
* @param[in] frameBuffer - Pointer to the frame buffer. This buffer will be considered "locked"
until the callback is called.
* @param[in] callback - The callback function to be called when buffer is no longer needed
* @param[in] userData - Optional pointer to be passed through to the callback function
* @return - TTV_EC_SUCCESS if function succeeds; error code otherwise
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_SubmitVideoFrame)(const uint8_t* frameBuffer,
TTV_BufferUnlockCallback callback,
void* userData);
/**
* TTV_SendActionMetaData - Send a singular action metadata point to Twitch's metadata service
* @param[in] authToken - The streamer's auth token
* @param[in] streamId - The stream's unique ID
* @param[in] name - A specific name for an event meant to be queryable
* @param[in] streamTime - Number of milliseconds into the broadcast for when event occurs
* @param[in] humanDescription - Long form string to describe the meaning of an event. Maximum length is 1000 characters
* @param[in] data - A valid JSON object that is the payload of an event. Values in this JSON object have to be strings. Maximum of 50 keys are allowed. Maximum length for values are 255 characters.
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_SendActionMetaData)(const TTV_AuthToken* authToken, uint64_t streamId,
const char* name, uint64_t streamTime,
const char* humanDescription, const char* data);
/**
* TTV_SendStartSpanMetaData - Send the beginning datapoint of an event that has a beginning and end
* @param[in] authToken - The streamer's auth token
* @param[in] streamId - The stream's unique ID
* @param[in] name - A specific name for an event meant to be queryable
* @param[in] streamTime - Number of milliseconds into the broadcast for when event occurs
* @param[out] sequenceId - A unique sequenceId returned that associates a start and end event together
* @param[in] humanDescription - Long form string to describe the meaning of an event. Maximum length is 1000 characters
* @param[in] data - A valid JSON object that is the payload of an event. Values in this JSON object have to be strings. Maximum of 50 keys are allowed. Maximum length for values are 255 characters.
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_SendStartSpanMetaData)(const TTV_AuthToken* authToken, uint64_t streamId,
const char* name, uint64_t streamTime, unsigned long* sequenceId,
const char* humanDescription, const char* data);
/**
* TTV_SendEndSpanMetaData - Send the ending datapoint of an event that has a beginning and end.
* @param[in] authToken - The streamer's auth token
* @param[in] streamId - The stream's unique ID
* @param[in] name - A specific name for an event meant to be queryable
* @param[in] streamTime - Number of milliseconds into the broadcast for when event occurs
* @param[in] sequenceId - Associates a start and end event together. Use the correspoding sequenceId returned in TTV_SendStartSpanMetaData
* @param[in] humanDescription - Long form string to describe the meaning of an event. Maximum length is 1000 characters
* @param[in] data - A valid JSON object that is the payload of an event. Values in this JSON object have to be strings. Maximum of 50 keys are allowed. Maximum length for values are 255 characters.
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_SendEndSpanMetaData)(const TTV_AuthToken* authToken, uint64_t streamId,
const char* name, uint64_t streamTime, unsigned long sequenceId,
const char* humanDescription, const char* data);
/**
* TTV_SetStreamInfo - Send stream-related information to Twitch
* @param[in] authToken - The authentication token previously obtained
* @param[in] channel - The channel name that will have its stream info set.
* @param[in] streamInfoToBeSet - The stream-related information to send.
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_SetStreamInfo)(const TTV_AuthToken* authToken, const char* channel, const TTV_StreamInfoForSetting* streamInfoToSet);
/**
* TTV_GetUserInfo - Returns user-related information from Twitch
* @param[in] authToken - The authentication token previously obtained
* @param[in] callback - The callback function to be called when user info is retrieved
* @param[in] userData - Optional pointer to be passed through to the callback function
* @param[out] userInfo - The user-related information.
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_GetUserInfo)(const TTV_AuthToken* authToken,
TTV_TaskCallback callback,
void* userData,
TTV_UserInfo* userInfo);
/**
* TTV_StreamInfo - Returns stream-related information from Twitch
* @param[in] authToken - The authentication token previously obtained
* @param[in] callback - The callback function to be called when user info is retrieved
* @param[in] userData - Optional pointer to be passed through to the callback function
* @param[in] channel - The channel name that will have its stream info set.
* @param[out] streamInfo - The stream-related information.
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_GetStreamInfo)(const TTV_AuthToken* authToken,
TTV_TaskCallback callback,
void* userData,
const char* channel,
TTV_StreamInfo* streamInfo);
/**
* TTV_GetArchivingState - Returns whether video recording is enabled for the channel and
* if not, a cure URL that lets the user to enable recording for the channel
* @param[in] authToken - The authentication token previously obtained
* @param[in] callback - The callback function to be called when user info is retrieved
* @param[in] userData - Optional pointer to be passed through to the callback function
* @param[out] archivingState - The channel archiving state
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_GetArchivingState)(const TTV_AuthToken* authToken,
TTV_TaskCallback callback,
void* userData,
TTV_ArchivingState* archivingState);
/**
* TTV_RunCommercial - Runs a commercial on the channel
* @param[in] authToken - The authentication token previously obtained
* @param[in] callback - The callback function to be called when the web API has been called
* @param[in] userData - Optional pointer to be passed through to the callback function
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_RunCommercial)(const TTV_AuthToken* authToken,
TTV_TaskCallback callback,
void* userData);
/**
* TTV_GetGameLiveStreams - Gets 25 of the current live streams of the given game
* @param[in] gameName - Name of the game to get the streams for
* @param[in] callback - The callback function to be called when the web API has been called
* @param[in] userData - Optional pointer to be passed through to the callback function
* @param[out] gameStreamList - List of the current live streams for the game
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_GetGameLiveStreams)(const char* gameName,
TTV_TaskCallback callback,
void* userData,
TTV_LiveGameStreamList* gameStreamList);
/**
* TTV_FreeGameLiveStreamList - Must be called after getting the list of live streams for a game to free the list
* @param[in] gameStreamList - Pointer to the TTV_LiveGameStreamList struct to be freed
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_FreeGameLiveStreamList)(TTV_LiveGameStreamList* gameStreamList);
/**
* TTV_GetVolume - Get the volume level for the given device
* @param[in] device - The device to get the volume for
* @param[out] volume - The volume level (0.0 to 1.0)
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_GetVolume)(TTV_AudioDeviceType device, float* volume);
/**
* TTV_SetVolume - Set the volume level for the given device
* @param[in] device - The device to set the volume for
* @param[in] volume - The volume level (0.0 to 1.0)
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_SetVolume)(TTV_AudioDeviceType device, float volume);
/**
* TTV_Pause - Pause the video. The SDK will generate frames (e.g. a pause animation)
* util TTV_Unpause is called. Audio will continue to be captured/streamed; you can
* mute audio by setting the volume to <= 0. Submitting a video frame will unpause the stream.
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_PauseVideo)();
/**
* TTV_Stop - Stops the stream. This function is asynchronous if a valid callback is provided.
* @param[in] callback The callback to call when the operation has completed. Can be null to force this function to be synchronous.
* @param[in] userData - Client data to pass along in the callback.
* @return - TTV_EC_SUCCESS if function succeeds; error code otherwise
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_Stop)(TTV_TaskCallback callback, void* userData);
/**
* TTV_Shutdown - Shut down the Twitch Broadcasting SDK
* @return - TTV_EC_SUCCESS if function succeeds; error code otherwise
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_Shutdown)();
/**
* TTV_SetTraceLevel - Sets the minimum threshold for what type of trace messages should be included into the log.
* For example, if TTV_EC_ERROR is set, only error messages will be added to the log.
* If TTV_EC_WARNING is set, both warning messages and error messages will be added to the log (since TTV_EC_ERROR passes the minimum threshold set by TTV_EC_WARNING).
* @return - TTV_EC_SUCCESS
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_SetTraceLevel)(TTV_MessageLevel traceLevel);
/**
* TTV_SetTraceOutput - Sets the file path into which to log tracing.
* @return - TTV_EC_SUCCESS if function succeeds; TTV_EC_CANNOT_OPEN_FILE if the file cannot be opened.
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_SetTraceOutput)(const wchar_t* outputFileName);
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_RegisterStatsCallback)(TTV_StatCallback callback);
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_RemoveStatsCallback)(TTV_StatCallback callback);
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_PollStats)();
/**
* TTV_ErrorToString - Converts an error code into a human-readable UTF8 string.
* @param[in] err - The error code to translate.
* @return - The string for the error code.
*/
typedef const char* TTV_CALLSPEC (*TTV_ErrorToString)(TTV_ErrorCode err);
/**
* TTV_GetGameNameList - Retrieves the list of games which match the given string. All arguments except userData must be non-null and str must not be empty.
* When the callback is called and is successful gameList will be filled with the game information. Be sure to free the game list
* via TTV_FreeGameNameList.
*
* @param[in] str - The string to match.
* @param[in] callback - The callback which will be called when the result is ready.
* @param[in] games - The location the result will be written to.
* @param[in] userData - Data passed along in the callback.
* @return - TTV_EC_SUCCESS is the request is issued correctly.
* TTV_WRN_PREV_GAME_NAME_MATCH_REQUEST_DROPPED if a previous request was dropped because they're being issues too quickly.
* TTV_EC_INVALID_ARG if any arguments are invalid.
*/
typedef TTV_ErrorCode TTV_CALLSPEC (* TTV_GetGameNameList)(const char* str, TTV_TaskCallback callback, TTV_GameInfoList* gameList, void* userData);
/**
* TTV_FreeGameNameList - Must be called after a reply from TTV_GetGameNameList.
* @param[in] gameList - Pointer to the TTV_GameInfoList struct to be freed.
*/
typedef TTV_ErrorCode TTV_CALLSPEC (*TTV_FreeGameNameList)(TTV_GameInfoList* gameList);
#ifdef __cplusplus
}
#endif
#endif /* TTVSDK_TWITCH_SDK_H */

View file

@ -0,0 +1,634 @@
/********************************************************************************************
* Twitch Broadcasting SDK
*
* This software is supplied under the terms of a license agreement with Justin.tv Inc. and
* may not be copied or used except in accordance with the terms of that agreement
* Copyright (c) 2012-2013 Justin.tv Inc.
*********************************************************************************************/
#ifndef TTVSDK_TWITCH_SDK_TYPES_H
#define TTVSDK_TWITCH_SDK_TYPES_H
#include <stddef.h>
#include <stdint.h>
#include "errno.h"
#define TTVSDK_API
/**
* Specifies that the string is encoded as UTF-8.
*/
typedef char utf8char;
typedef unsigned int uint;
/**
* TTV_MessageLevel - Level of debug messages to be printed
*/
typedef enum
{
TTV_ML_DEBUG,
TTV_ML_INFO,
TTV_ML_WARNING,
TTV_ML_ERROR,
TTV_ML_CHAT,
TTV_ML_NONE // this must appear last (since a given value and the values greater are the ones logged - "none" at the highest value effectively disables logging)
} TTV_MessageLevel;
/**
* Memory allocation callback function signatures
*/
typedef void* (*TTV_AllocCallback) (size_t size, size_t alignment);
typedef void (*TTV_FreeCallback) (void* ptr);
/**
* TTV_MemCallbacks - Pointers to memory allocation callback functions provided by the client
*/
typedef struct
{
size_t size; /* Size of the struct */
TTV_AllocCallback allocCallback; /* Memory allocation callback function provided by the client */
TTV_FreeCallback freeCallback; /* Memory deallocation callback function provided by the client */
} TTV_MemCallbacks;
/**
* TTV_AuthParams - Authentication parameters for broadcasting on Twitch. A broadcast key is ultimately needed; but it may be obtained by using username/password.
*/
typedef struct
{
size_t size; /* Size of the struct */
const char* userName; /* Twitch user name */
const char* password; /* Twitch password */
const char* clientSecret; /* Twitch client secret */
} TTV_AuthParams;
/**
* TTV_IngestServer - Represents a Twitch Ingest server
*/
#define kMaxServerNameLength 255
#define kMaxServerUrlLength 255
typedef struct
{
char serverName[kMaxServerNameLength+1]; /* The ingest server name */
char serverUrl[kMaxServerUrlLength+1]; /* The ingest server URL */
bool defaultServer; /* Is this the default ingest server to use */
} TTV_IngestServer;
/**
* TTV_IngestList - A list of ingest servers
*/
typedef struct
{
TTV_IngestServer* ingestList;
uint ingestCount;
} TTV_IngestList;
/**
* TTV_PixelFormat - Supported input frame pixel formats
*/
typedef enum
{
TTV_PF_BGRA = 0x00010203,
TTV_PF_ABGR = 0x01020300,
TTV_PF_RGBA = 0x02010003,
TTV_PF_ARGB = 0x03020100
} TTV_PixelFormat;
/**
* TTV_EncodingCpuUsage - Set CPU usage level for video encoding
*
*/
typedef enum
{
TTV_ECU_LOW,
TTV_ECU_MEDIUM,
TTV_ECU_HIGH
} TTV_EncodingCpuUsage;
/**
* TTV_VideoEncoder - The video encoder to use
*/
typedef enum
{
TTV_VID_ENC_DEFAULT = -1,
TTV_VID_ENC_INTEL = 0,
TTV_VID_ENC_X264 = 1,
TTV_VID_ENC_APPLE = 2
} TTV_VideoEncoder;
#define TTV_MIN_BITRATE 230
#define TTV_MAX_BITRATE 3500
#define TTV_MIN_FPS 10
#define TTV_MAX_FPS 60
#define TTV_MAX_WIDTH 1920 /* Width and height must be multiples of 16 */
#define TTV_MAX_HEIGHT 1200
/**
* TTV_VideoParams - Video parameters
*/
typedef struct
{
size_t size; /* Size of the struct */
uint outputWidth; /* Width of the output video stream in pixels */
uint outputHeight; /* Height of the output video stream in pixels */
TTV_PixelFormat pixelFormat; /* Frame pixel format */
uint maxKbps; /* Max bit rate */
uint targetFps; /* Target frame rate */
TTV_EncodingCpuUsage encodingCpuUsage; /* CPU usage level for video encoding */
bool disableAdaptiveBitrate; /* By default the SDK attempts to match the targetBitrate (set in maxKbps above) in cases where frames are submitted at a lower rate than target FPS. You can disable this feature */
bool verticalFlip; /* Flip the frames vertically - This incurs a performance penalty on some platforms (e.g. iOS) */
} TTV_VideoParams;
/**
* TTV_AudioEncoder - The audio encoder to use
*/
typedef enum
{
TTV_AUD_ENC_DEFAULT = -1,
TTV_AUD_ENC_LAMEMP3 = 0,
TTV_AUD_ENC_APPLEAAC = 1,
} TTV_AudioEncoder;
/**
* TTV_AudioSampleFormat - Supported input audio sample formats
*/
typedef enum
{
TTV_ASF_PCM_S16 /* PCM signed 16-bit */
} TTV_AudioSampleFormat;
/**
* TTV_AudioParams - Audio parameters
*/
typedef struct
{
size_t size; /* Size of the struct */
bool audioEnabled; /* Is audio enabled? */
} TTV_AudioParams;
typedef enum TTV_AudioDeviceType
{
TTV_PLAYBACK_DEVICE,
TTV_RECORDER_DEVICE,
TTV_DEVICE_NUM
} TTV_AudioDeviceType;
/**
* TTV_ErrorCode
*/
typedef enum
{
// Warnings //////////////////////////////////////////////////
TTV_EC_WARNING_START = -1000,
TTV_WRN_MUTEX_LOCKED,
TTV_WRN_FAILED_TO_INIT_MIC_CAPTURE,
TTV_WRN_NOMOREDATA,
TTV_WRN_FRAMES_QUEUEING,
TTV_WRN_MUTEX_NOT_AQUIRED,
TTV_WRN_PREV_GAME_NAME_MATCH_REQUEST_DROPPED, //!< A previously pending request for matching game names was dropped in favor of the most recent request.
TTV_WRN_DEPRECATED,
TTV_WRN_CHAT_MESSAGE_SPAM_DISCARDED, //!< The client is submitting chat messages too quickly and the message was discarded.
TTV_WRN_WAIT_TIMEOUT, //!< a thread wait timed out
// Success //////////////////////////////////////////////////
TTV_EC_SUCCESS = 0,
// Errors //////////////////////////////////////////////////
TTV_EC_UNKNOWN_ERROR,
TTV_EC_CANNOT_OPEN_FILE,
TTV_EC_ALREADY_INITIALIZED,
TTV_EC_CANNOT_WRITE_TO_FILE,
TTV_EC_CANNOT_CREATE_MUTEX,
TTV_EC_CANNOT_DESTROY_MUTEX,
TTV_EC_COULD_NOT_TAKE_MUTEX,
TTV_EC_COULD_NOT_RELEASE_MUTEX,
TTV_EC_INVALID_MUTEX,
TTV_EC_WAIT_TIMED_OUT,
TTV_EC_INVALID_ARG,
TTV_EC_NOT_INITIALIZED,
TTV_EC_AUTHENTICATION,
TTV_EC_INVALID_AUTHTOKEN,
TTV_EC_MEMORY,
TTV_EC_ALIGN16_REQUIRED,
TTV_EC_UNSUPPORTED_INPUT_FORMAT,
TTV_EC_UNSUPPORTED_OUTPUT_FORMAT,
TTV_EC_INVALID_RESOLUTION,
TTV_EC_INVALID_FPS,
TTV_EC_INVALID_BITRATE,
TTV_EC_FAILED_TO_INIT_SPEAKER_CAPTURE,
TTV_EC_FRAME_QUEUE_FULL,
TTV_EC_CURL_ERROR,
TTV_EC_INVALID_CLIENTID,
TTV_EC_INVALID_CHANNEL_NAME,
TTV_EC_INVALID_CACERT_BUNDLE_FILE,
TTV_EC_API_REQUEST_FAILED,
TTV_EC_API_REQUEST_TIMEDOUT,
TTV_EC_INVALID_API_CURL_PARAMS,
TTV_EC_WEBAPI_RESULT_INVALID_JSON,
TTV_EC_WEBAPI_RESULT_NO_AUTHTOKEN,
TTV_EC_WEBAPI_RESULT_NO_STREAMKEY,
TTV_EC_WEBAPI_RESULT_NO_CHANNELNAME,
TTV_EC_WEBAPI_RESULT_NO_INGESTS,
TTV_EC_WEBAPI_RESULT_NO_RECORDING_STATUS,
TTV_EC_WEBAPI_RESULT_NO_STREAMINFO,
TTV_EC_WEBAPI_RESULT_INVALID_VIEWERS,
TTV_EC_WEBAPI_RESULT_NO_USERNAME,
TTV_EC_WEBAPI_RESULT_NO_USER_DISPLAY_NAME,
TTV_EC_NO_STREAM_KEY,
TTV_EC_NEED_TO_LOGIN,
TTV_EC_INVALID_VIDEOFRAME,
TTV_EC_INVALID_BUFFER,
TTV_EC_INVALID_CALLBACK,
TTV_EC_INVALID_JSON,
TTV_EC_NO_SPSPPS,
TTV_EC_NO_D3D_SUPPORT,
TTV_EC_NO_INGEST_SERVER_AVAILABLE,
TTV_EC_INVALID_INGEST_SERVER,
TTV_EC_CANNOT_SUSPEND_THREADSYNC,
TTV_EC_CANNOT_SIGNAL_THREADSYNC,
TTV_EC_INVALID_ENCODER,
TTV_EC_AUDIO_DEVICE_INIT_FAILED,
TTV_EC_INVALID_SAMPLERATE,
TTV_EC_X264_INVALID_PRESET,
TTV_EC_X264_INVALID_PROFILE,
TTV_EC_FLV_UNABLE_TO_OPEN_FILE,
TTV_EC_FLV_FILE_NOT_OPEN,
TTV_EC_FLV_UNSUPPORTED_AUDIO_RATE,
TTV_EC_FLV_UNSUPPORTED_AUDIO_CODEC,
TTV_EC_RTMP_WRONG_PROTOCOL_IN_URL,
TTV_EC_RTMP_UNABLE_TO_SEND_DATA,
TTV_EC_RTMP_INVALID_FLV_PACKET,
TTV_EC_RTMP_TIMEOUT,
// Mac audio capture
TTV_EC_MAC_INPUT_Q_SETUP_FAILED,
TTV_EC_MAC_INPUT_Q_BUFFER_SETUP_FAILED,
TTV_EC_MAC_INPUT_Q_START_FAILED,
// intel encoder
TTV_EC_INTEL_FAILED_SESSION_INIT,
TTV_EC_INTEL_FAILED_VPP_INIT,
TTV_EC_INTEL_FAILED_ENCODER_INIT,
TTV_EC_INTEL_FAILED_SURFACE_ALLOCATION,
TTV_EC_INTEL_FAILED_TASKPOLL_INIT,
TTV_EC_INTEL_NO_FREE_TASK,
TTV_EC_INTEL_NO_FREE_SURFACE,
// apple encoder
TTV_EC_APPLEENCODER_FAILED_START,
TTV_EC_APPLEENCODER_FAILED_FRAME_SUBMISSION,
// lame mp3 encoder
TTV_EC_LAMEMP3_FAILED_INIT,
TTV_EC_LAMEMP3_FAILED_SHUTDOWN,
// apple aac encoder
TTV_EC_APPLEAAC_FAILED_INIT,
TTV_EC_APPLEAAC_FAILED_ENCODING,
TTV_EC_APPLEAAC_FAILED_SHUTDOWN,
// TODO: map mac errors onto winsock errors
TTV_EC_REQUEST_PENDING,
TTV_EC_WSASTARTUP_FAILED,
TTV_EC_WSACLEANUP_FAILED,
TTV_EC_SOCKET_GETADDRINFO_FAILED,
TTV_EC_SOCKET_CREATE_FAILED,
TTV_EC_SOCKET_CONNECT_FAILED,
TTV_EC_SOCKET_SEND_ERROR,
TTV_EC_SOCKET_RECV_ERROR,
TTV_EC_SOCKET_IOCTL_ERROR,
TTV_EC_SOCKET_ERR = 1000,
TTV_EC_SOCKET_EINTR = TTV_EC_SOCKET_ERR + 4,
TTV_EC_SOCKET_EBADF = TTV_EC_SOCKET_ERR + 9,
TTV_EC_SOCKET_EACCES = TTV_EC_SOCKET_ERR + 13,
TTV_EC_SOCKET_EFAULT = TTV_EC_SOCKET_ERR + 14,
TTV_EC_SOCKET_EINVAL = TTV_EC_SOCKET_ERR + 22,
TTV_EC_SOCKET_EMFILE = TTV_EC_SOCKET_ERR + 24,
TTV_EC_SOCKET_EWOULDBLOCK = TTV_EC_SOCKET_ERR + 35,
TTV_EC_SOCKET_EINPROGRESS = TTV_EC_SOCKET_ERR + 36,
TTV_EC_SOCKET_EALREADY = TTV_EC_SOCKET_ERR + 37,
TTV_EC_SOCKET_ENOTSOCK = TTV_EC_SOCKET_ERR + 38,
TTV_EC_SOCKET_EDESTADDRREQ = TTV_EC_SOCKET_ERR + 39,
TTV_EC_SOCKET_EMSGSIZE = TTV_EC_SOCKET_ERR + 40,
TTV_EC_SOCKET_EPROTOTYPE = TTV_EC_SOCKET_ERR + 41,
TTV_EC_SOCKET_ENOPROTOOPT = TTV_EC_SOCKET_ERR + 42,
TTV_EC_SOCKET_EPROTONOSUPPORT = TTV_EC_SOCKET_ERR + 43,
TTV_EC_SOCKET_ESOCKTNOSUPPORT = TTV_EC_SOCKET_ERR + 44,
TTV_EC_SOCKET_EOPNOTSUPP = TTV_EC_SOCKET_ERR + 45,
TTV_EC_SOCKET_EPFNOSUPPORT = TTV_EC_SOCKET_ERR + 46,
TTV_EC_SOCKET_EAFNOSUPPORT = TTV_EC_SOCKET_ERR + 47,
TTV_EC_SOCKET_EADDRINUSE = TTV_EC_SOCKET_ERR + 48,
TTV_EC_SOCKET_EADDRNOTAVAIL = TTV_EC_SOCKET_ERR + 49,
TTV_EC_SOCKET_ENETDOWN = TTV_EC_SOCKET_ERR + 50,
TTV_EC_SOCKET_ENETUNREACH = TTV_EC_SOCKET_ERR + 51,
TTV_EC_SOCKET_ENETRESET = TTV_EC_SOCKET_ERR + 52,
TTV_EC_SOCKET_ECONNABORTED = TTV_EC_SOCKET_ERR + 53,
TTV_EC_SOCKET_ECONNRESET = TTV_EC_SOCKET_ERR + 54,
TTV_EC_SOCKET_ENOBUFS = TTV_EC_SOCKET_ERR + 55,
TTV_EC_SOCKET_EISCONN = TTV_EC_SOCKET_ERR + 56,
TTV_EC_SOCKET_ENOTCONN = TTV_EC_SOCKET_ERR + 57,
TTV_EC_SOCKET_ESHUTDOWN = TTV_EC_SOCKET_ERR + 58,
TTV_EC_SOCKET_ETOOMANYREFS = TTV_EC_SOCKET_ERR + 59,
TTV_EC_SOCKET_ETIMEDOUT = TTV_EC_SOCKET_ERR + 60,
TTV_EC_SOCKET_ECONNREFUSED = TTV_EC_SOCKET_ERR + 61,
TTV_EC_SOCKET_ELOOP = TTV_EC_SOCKET_ERR + 62,
TTV_EC_SOCKET_ENAMETOOLONG = TTV_EC_SOCKET_ERR + 63,
TTV_EC_SOCKET_EHOSTDOWN = TTV_EC_SOCKET_ERR + 64,
TTV_EC_SOCKET_EHOSTUNREACH = TTV_EC_SOCKET_ERR + 65,
TTV_EC_SOCKET_ENOTEMPTY = TTV_EC_SOCKET_ERR + 66,
TTV_EC_SOCKET_EPROCLIM = TTV_EC_SOCKET_ERR + 67,
TTV_EC_SOCKET_EUSERS = TTV_EC_SOCKET_ERR + 68,
TTV_EC_SOCKET_EDQUOT = TTV_EC_SOCKET_ERR + 69,
TTV_EC_SOCKET_ESTALE = TTV_EC_SOCKET_ERR + 70,
TTV_EC_SOCKET_EREMOTE = TTV_EC_SOCKET_ERR + 71,
TTV_EC_SOCKET_SYSNOTREADY = TTV_EC_SOCKET_ERR + 91,
TTV_EC_SOCKET_VERNOTSUPPORTED = TTV_EC_SOCKET_ERR + 92,
TTV_EC_SOCKET_NOTINITIALISED = TTV_EC_SOCKET_ERR + 93,
TTV_EC_SOCKET_EDISCON = TTV_EC_SOCKET_ERR + 101,
TTV_EC_SOCKET_ENOMORE = TTV_EC_SOCKET_ERR + 102,
TTV_EC_SOCKET_ECANCELLED = TTV_EC_SOCKET_ERR + 103,
TTV_EC_SOCKET_EINVALIDPROCTABLE = TTV_EC_SOCKET_ERR + 104,
TTV_EC_SOCKET_EINVALIDPROVIDER = TTV_EC_SOCKET_ERR + 105,
TTV_EC_SOCKET_EPROVIDERFAILEDINIT = TTV_EC_SOCKET_ERR + 106,
TTV_EC_SOCKET_SYSCALLFAILURE = TTV_EC_SOCKET_ERR + 107,
TTV_EC_SOCKET_SERVICE_NOT_FOUND = TTV_EC_SOCKET_ERR + 108,
TTV_EC_SOCKET_TYPE_NOT_FOUND = TTV_EC_SOCKET_ERR + 109,
TTV_EC_SOCKET_E_NO_MORE = TTV_EC_SOCKET_ERR + 110,
TTV_EC_SOCKET_E_CANCELLED = TTV_EC_SOCKET_ERR + 111,
TTV_EC_SOCKET_EREFUSED = TTV_EC_SOCKET_ERR + 112,
TTV_EC_SOCKET_HOST_NOT_FOUND = TTV_EC_SOCKET_ERR + 1001,
TTV_EC_SOCKET_TRY_AGAIN = TTV_EC_SOCKET_ERR + 1002,
TTV_EC_SOCKET_NO_RECOVERY = TTV_EC_SOCKET_ERR + 1003,
TTV_EC_SOCKET_NO_DATA = TTV_EC_SOCKET_ERR + 1004,
TTV_EC_SOCKET_QOS_RECEIVERS = TTV_EC_SOCKET_ERR + 1005,
TTV_EC_SOCKET_QOS_SENDERS = TTV_EC_SOCKET_ERR + 1006,
TTV_EC_SOCKET_QOS_NO_SENDERS = TTV_EC_SOCKET_ERR + 1007,
TTV_EC_SOCKET_QOS_NO_RECEIVERS = TTV_EC_SOCKET_ERR + 1008,
TTV_EC_SOCKET_QOS_REQUEST_CONFIRMED = TTV_EC_SOCKET_ERR + 1009,
TTV_EC_SOCKET_QOS_ADMISSION_FAILURE = TTV_EC_SOCKET_ERR + 1010,
TTV_EC_SOCKET_QOS_POLICY_FAILURE = TTV_EC_SOCKET_ERR + 1011,
TTV_EC_SOCKET_QOS_BAD_STYLE = TTV_EC_SOCKET_ERR + 1012,
TTV_EC_SOCKET_QOS_BAD_OBJECT = TTV_EC_SOCKET_ERR + 1013,
TTV_EC_SOCKET_QOS_TRAFFIC_CTRL_ERROR = TTV_EC_SOCKET_ERR + 1014,
TTV_EC_SOCKET_QOS_GENERIC_ERROR = TTV_EC_SOCKET_ERR + 1015,
TTV_EC_SOCKET_QOS_ESERVICETYPE = TTV_EC_SOCKET_ERR + 1016,
TTV_EC_SOCKET_QOS_EFLOWSPEC = TTV_EC_SOCKET_ERR + 1017,
TTV_EC_SOCKET_QOS_EPROVSPECBUF = TTV_EC_SOCKET_ERR + 1018,
TTV_EC_SOCKET_QOS_EFILTERSTYLE = TTV_EC_SOCKET_ERR + 1019,
TTV_EC_SOCKET_QOS_EFILTERTYPE = TTV_EC_SOCKET_ERR + 1020,
TTV_EC_SOCKET_QOS_EFILTERCOUNT = TTV_EC_SOCKET_ERR + 1021,
TTV_EC_SOCKET_QOS_EOBJLENGTH = TTV_EC_SOCKET_ERR + 1022,
TTV_EC_SOCKET_QOS_EFLOWCOUNT = TTV_EC_SOCKET_ERR + 1023,
TTV_EC_SOCKET_QOS_EUNKOWNPSOBJ = TTV_EC_SOCKET_ERR + 1024,
TTV_EC_SOCKET_QOS_EPOLICYOBJ = TTV_EC_SOCKET_ERR + 1025,
TTV_EC_SOCKET_QOS_EFLOWDESC = TTV_EC_SOCKET_ERR + 1026,
TTV_EC_SOCKET_QOS_EPSFLOWSPEC = TTV_EC_SOCKET_ERR + 1027,
TTV_EC_SOCKET_QOS_EPSFILTERSPEC = TTV_EC_SOCKET_ERR + 1028,
TTV_EC_SOCKET_QOS_ESDMODEOBJ = TTV_EC_SOCKET_ERR + 1029,
TTV_EC_SOCKET_QOS_ESHAPERATEOBJ = TTV_EC_SOCKET_ERR + 1030,
TTV_EC_SOCKET_QOS_RESERVED_PETYPE = TTV_EC_SOCKET_ERR + 1031,
TTV_EC_SOCKET_SECURE_HOST_NOT_FOUND = TTV_EC_SOCKET_ERR + 1032,
TTV_EC_SOCKET_IPSEC_NAME_POLICY_ERROR = TTV_EC_SOCKET_ERR + 1033,
TTV_EC_SOCKET_END,
// chat
TTV_EC_CHAT_NOT_INITIALIZED, //!< The chat subsystem has not been initialized properly.
TTV_EC_CHAT_ALREADY_INITIALIZED, //!< The chat subsystem has already been initialized.
TTV_EC_CHAT_ALREADY_IN_CHANNEL, //!< Already in the channel.
TTV_EC_CHAT_INVALID_LOGIN, //!< Invalid login credentials.
TTV_EC_CHAT_INVALID_CHANNEL, //!< The named channel doesn't exist.
TTV_EC_CHAT_LOST_CONNECTION, //!< Lost connection to the chat server.
TTV_EC_CHAT_COULD_NOT_CONNECT, //!< Could not connect to the chat server.
TTV_EC_CHAT_NOT_IN_CHANNEL, //!< Not in the named channel.
TTV_EC_CHAT_INVALID_MESSAGE, //!< Not a valid message.
TTV_EC_CHAT_TOO_MANY_REQUESTS, //!< The request queue is growing too large and the request has been ignored.
TTV_EC_CHAT_LEAVING_CHANNEL, //!< In the middle of leaving the channel.
TTV_EC_CHAT_SHUTTING_DOWN, //!< The chat system is in the middle of shutting down and cannot be used currently.
TTV_EC_CHAT_ANON_DENIED, //!< Attempted to perform an action that anonymous connections are not allowed to do.
TTV_EC_CHAT_EMOTICON_DATA_NOT_READY, //!< The emoticon data is not ready to use.
TTV_EC_CHAT_EMOTICON_DATA_DOWNLOADING, //!< The emoticon data is already downloading.
TTV_EC_CHAT_EMOTICON_DATA_LOCKED, //!< The emoticon data has been locked by the client by a call to TTV_Chat_GetEmoticonData which has not been freed by TTV_Chat_FreeEmoticonData.
TTV_EC_CHAT_EMOTICON_DOWNLOAD_FAILED, //!< There were too many download errors while trying to fetch the emoticon data. TTV_EC_CHAT_ANON_DENIED //!< Attempted to perform an action that anonymous connections are not allowed to do.
//webcam
TTV_EC_WEBCAM_NO_PLATFORM_SUPPORT,
TTV_EC_WEBCAM_COULD_NOT_COMPLETE,
TTV_EC_WEBCAM_OUT_OF_MEMORY,
TTV_EC_WEBCAM_UNKNOWN_ERROR,
TTV_EC_WEBCAM_INVALID_PARAMETER,
TTV_EC_WEBCAM_INVALID_CAPABILITY,
TTV_EC_WEBCAM_BUFFER_NOT_BIG_ENOUGH,
TTV_EC_WEBCAM_DEVICE_NOT_STARTED,
TTV_EC_WEBCAM_DEVICE_ALREADY_STARTED,
TTV_EC_WEBCAM_DEVICE_NOT_FOUND,
TTV_EC_WEBCAM_FRAME_NOT_AVAILABLE,
TTV_EC_WEBCAM_NOT_INITIALIZED,
TTV_EC_WEBCAM_FAILED_TO_START,
TTV_EC_WEBCAM_LEFT_IN_UNSAFE_STATE,
TTV_EC_WEBCAM_UNSUPPORTED_SOURCE_FORMAT,
TTV_EC_WEBCAM_UNSUPPORTED_TARGET_FORMAT,
TTV_EC_INVALID_STRUCT_SIZE, //!< The size field of the struct does not have the expected value. Some fields may have been added to the struct and you may have set them and recompile your code.
TTV_EC_STREAM_ALREADY_STARTED, //!< The requested operation can't be serviced because the broadcast has already been started.
TTV_EC_STREAM_NOT_STARTED, //!< The requested operation can't be serviced because the broadcast not been started.
TTV_EC_REQUEST_ABORTED, //!< The request was aborted and did not finish.
TTV_EC_FRAME_QUEUE_TOO_LONG //!< The network is backing up because video settings are too high for the internet connection. Stop the stream and restart with lower settings.
} TTV_ErrorCode;
typedef enum
{
TTV_ST_RTMPSTATE,
TTV_ST_RTMPDATASENT
} TTV_StatType;
#define TTV_RTMP_LAST_CONNECT_STATE 6
#define TTV_FAILED(err) ( (err) > TTV_EC_SUCCESS )
#define TTV_SUCCEEDED(err) ( (err) <= TTV_EC_SUCCESS)
#define TTV_RETURN_ON_NULL(ptr,err) { if ( (ptr) == nullptr) return err; }
#define ASSERT_ON_ERROR(err) {assert ( (err) <= TTV_EC_SUCCESS ); }
#define TTV_TO_WSA_ERROR(ttv_ec) (int)(ttv_ec-TTV_EC_SOCKET_ERR+WSABASEERR)
#define WSA_TO_TTV_ERROR(wsa_ec) (TTV_ErrorCode) (wsa_ec-WSABASEERR+TTV_EC_SOCKET_ERR)
/**
* Callback signature for buffer unlock
*/
typedef void (*TTV_BufferUnlockCallback) (const uint8_t* buffer, void* userData);
/**
* Callback signature for asynchronous tasks
*/
typedef void (*TTV_TaskCallback) (TTV_ErrorCode result, void* userData);
/**
* Callback signature for Stats reporting
*/
typedef void (*TTV_StatCallback) (TTV_StatType type, uint64_t data);
/**
* TTV_VideoFrame - Input video frame parameters
*/
typedef struct
{
size_t size; /* Size of the struct */
uint8_t* frameBuffer; /* Raw bytes of the frame - the frame resolution MUST match the resolution of the output video */
TTV_BufferUnlockCallback callback; /* callback that gets called when VideoFrame is no longer needed */
void* userData; /* userData passed to the callback */
uint64_t mTimeStamp; /* For internal use */
} TTV_VideoFrame;
/**
* TTV_AuthToken - The max length of a Twitch authentication token.
*/
const uint kAuthTokenBufferSize = 128;
/**
* TTV_AuthToken - The authentication token returned after successfully authenticating with username and password.
*/
typedef struct
{
char data[kAuthTokenBufferSize]; /* The token data. */
} TTV_AuthToken;
/**
* TTV_UserInfo - The user name
*/
#define kMaxUserNameLength 63
typedef struct
{
size_t size; /* The size of the struct. */
char displayName[kMaxUserNameLength+1]; /* The displayed name */
char name[kMaxUserNameLength+1]; /* The user name */
} TTV_UserInfo;
/**
* TTV_ChannelInfo - The channel info
*/
#define kMaxChannelUrlLength 255
typedef struct
{
size_t size; /* The size of the struct. */
char name[kMaxUserNameLength+1]; /* The channel name */
char displayName[kMaxUserNameLength+1]; /* The displayed channel name (which may be different) */
char channelUrl[kMaxChannelUrlLength+1]; /* The URL to that channel */
} TTV_ChannelInfo;
/**
* TTV_StreamInfo - The stream info
*/
typedef struct
{
size_t size; /* The size of the struct. */
int viewers; /* The current viewer count. */
uint64_t streamId; /* The unique id of the stream. */
} TTV_StreamInfo;
/**
* TTV_StreamInfoForSetting - The stream info
*/
#define kMaxStreamTitleLength 255
#define kMaxGameNameLength 255
typedef struct
{
size_t size; /* The size of the struct. */
char streamTitle[kMaxStreamTitleLength+1]; /* The title of the stream. If the first character is null, this parameter is ignored. */
char gameName[kMaxGameNameLength+1]; /* The name of the game being played. If the first character is null, this parameter is ignored. */
} TTV_StreamInfoForSetting;
/**
* TTV_RecordingStatus - The Video recording status of the channel
*/
#define kMaxCureUrlLength 255
typedef struct
{
size_t size; /* The size of the struct. */
bool recordingEnabled; /* Recording is enabled/disabled for the channel */
char cureUrl[kMaxCureUrlLength+1]; /* The URL for where the user can go to enable video recording for the channel */
} TTV_ArchivingState;
/**
* TTV_GameInfo - Display information about a game.
*/
typedef struct
{
char name[kMaxGameNameLength+1]; /* The display name of the game. */
int popularity; /* A popularity rating for the game. */
int id; /* The game's unique id. */
} TTV_GameInfo;
/**
* TTV_GameInfoList - A list of game info structs.
*/
typedef struct
{
TTV_GameInfo* list; /* The array of game info entries */
unsigned int count; /* The number of entries in the array. */
} TTV_GameInfoList;
/**
* TTV_GameLiveStreamInfo - Information about a live stream of a particular game
*/
typedef struct
{
char channelUrl[kMaxChannelUrlLength+1];
char previewUrlTemplate[kMaxChannelUrlLength+1];
char streamTitle[kMaxStreamTitleLength+1];
char channelDisplayName[kMaxUserNameLength+1];
unsigned int viewerCount;
} TTV_LiveGameStreamInfo;
/**
* TTV_LiveGameStreamList - List of live streams of a given game
*/
typedef struct
{
TTV_LiveGameStreamInfo* list; /* The array of live game stream info entries */
unsigned int count; /* The number of entries in the array */
} TTV_LiveGameStreamList;
/**
* All the valid flags for TTV_Start()
*/
#define TTV_Start_BandwidthTest 0x1
#endif /* TTVSDK_TWITCH_SDK_TYPES_H */

View file

@ -0,0 +1,316 @@
/********************************************************************************************
* Twitch Broadcasting SDK
*
* This software is supplied under the terms of a license agreement with Justin.tv Inc. and
* may not be copied or used except in accordance with the terms of that agreement
* Copyright (c) 2012-2013 Justin.tv Inc.
*********************************************************************************************/
#ifndef TTVSDK_TWITCH_WEBCAM_H
#define TTVSDK_TWITCH_WEBCAM_H
#include "twitchsdktypes.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* TTV_WebCamDeviceChange - Listing of the events which occur when a new device is plugged in or a device is unplugged from the system.
*/
typedef enum
{
TTV_WEBCAM_DEVICE_FOUND, //!< The device was plugged in and is ready to be started.
TTV_WEBCAM_DEVICE_LOST //!< The device was unplugged and is unavailable. If it was capturing you will not receive a stop notification.
} TTV_WebCamDeviceChange;
/**
* TTV_WebCamDeviceStatus - Listing of the states a device may be in once it is available in the system.
*/
typedef enum
{
TTV_WEBCAM_DEVICE_UNINITIALIZED, //!< The device hasn't been initialized.
TTV_WEBCAM_DEVICE_STARTED, //!< The device is currently capturing.
TTV_WEBCAM_DEVICE_STOPPED //!< The device is not currently capturing.
} TTV_WebCamDeviceStatus;
/**
* TTV_WebcamFormat - Listing of the various formats a device may return a buffer in. If you are unable to handle a buffer format in your application
* you may call TTV_WebCam_ConvertToRGBA to convert the buffer to RGBA.
*/
typedef enum
{
TTV_WEBCAM_FORMAT_UNKNOWN,
// compressed video types
//H264, // Not supported for now, since each frame can have a different size
// NOTE: The following format names do not match their actual memory layout.
// For example, ARGB32 is actually laid out in memory as BGRA.
// This naming is inconsistent with the rest of the SDK (which has names that match the memory layout).
// The reasoning for this is to match Direct3D, which also names things backwards.
// That way when a webcam provides ARGB a user can create a texture of ARGB and not be confused.
// See http://msdn.microsoft.com/en-us/library/windows/desktop/bb153349%28v=vs.85%29.aspx
// NOTE: The following format names do not match their actual memory layout.
// For example, ARGB32 is actually laid out in memory as BGRA.
// This naming is inconsistent with the rest of the SDK (which has names that match the memory layout).
// The reasoning for this is to match Direct3D, which also names things backwards.
// That way when a webcam provides ARGB a user can create a texture of ARGB and not be confused.
// See http://msdn.microsoft.com/en-us/library/windows/desktop/bb153349%28v=vs.85%29.aspx
// raw rgb types
TTV_WEBCAM_FORMAT_RGB1, // 1 bit per pixel, palettized
TTV_WEBCAM_FORMAT_RGB4, // 4 bpp, palettized
TTV_WEBCAM_FORMAT_RGB8, // 8 bpp, palettized
TTV_WEBCAM_FORMAT_RGB555, // 16 bpp, XRRRRRGG GGGBBBBB
TTV_WEBCAM_FORMAT_RGB565, // 16 bpp, RRRRRGGG GGGBBBBB
TTV_WEBCAM_FORMAT_RGB24, // 24 bpp, R8G8B8
TTV_WEBCAM_FORMAT_XRGB32, // 32 bpp, B8G8R8X8
TTV_WEBCAM_FORMAT_ARGB1555, // 16 bpp, 1 bit alpha, ARRRRRGG GGGBBBBB
TTV_WEBCAM_FORMAT_ARGB32, // 32 bpp, 8 bits alpha, B8G8R8A8
TTV_WEBCAM_FORMAT_ARGB4444, // 16 bpp, 4 bits alpha
TTV_WEBCAM_FORMAT_B10G10R10A2, // 32 bpp, 10 RGB, 2 alpha, BBBBBBBB BBGGGGGG GGGGRRRR RRRRRRAA
TTV_WEBCAM_FORMAT_R10G10B10A2, // 32 bpp, 10 RGB, 2 alpha, RRRRRRRR RRGGGGGG GGGGBBBB BBBBBBAA
// raw yuv types
TTV_WEBCAM_FORMAT_AYUV, // AYUV 4:4:4 packed 8 bpp
TTV_WEBCAM_FORMAT_YUY2, // YUY2 4:2:2 packed 8 bpp
TTV_WEBCAM_FORMAT_UYVY, // UYVY 4:2:2 packed 8 bpp
TTV_WEBCAM_FORMAT_IMC1, // IMC1 4:2:0 planar 8 bpp
TTV_WEBCAM_FORMAT_IMC2, // IMC2 4:2:0 planar 8 bpp
TTV_WEBCAM_FORMAT_IMC3, // IMC3 4:2:0 planar 8 bpp
TTV_WEBCAM_FORMAT_IMC4, // IMC4 4:2:0 planar 8 bpp
TTV_WEBCAM_FORMAT_YV12, // YV12 4:2:0 planar 8 bpp
TTV_WEBCAM_FORMAT_NV12 // NV12 4:2:0 planar 8 bpp
} TTV_WebcamFormat;
/**
* TTV_WebcamResolution - The resolution of an image.
*/
typedef struct
{
unsigned int height; //!< The buffer height.
unsigned int width; //!< The buffer width.
} TTV_WebcamResolution;
/**
* TTV_WebCamDeviceCapability - The properties of a mode in which a device can capture. Devices usually support more than one capability.
*/
typedef struct
{
unsigned int capabilityIndex; //!< The unique index of the capability which is not simply the index in the list.
TTV_WebcamResolution resolution; //!< The resolution of the capability.
uint32_t frameRate; //!< The approximate frame rate in frames per second.
TTV_WebcamFormat format; //!< The buffer format.
bool isTopToBottom; //!< Whether or not the buffer is packed from top to bottom.
bool isNative; //!< Whether or not a conversion from the raw buffer needs to be done to provide this format. Native formats are more efficient.
} TTV_WebCamDeviceCapability;
/**
* TTV_WebCamDeviceCapabilityList - A list of capabilities for the device.
*/
typedef struct
{
TTV_WebCamDeviceCapability* list; //!< The list.
unsigned int count; //!< The number of elements in the list.
} TTV_WebCamDeviceCapabilityList;
#define kMaxDeviceNameLength 64 //!< The max number of characters in the friendly name of a device.
#define kMaxDeviceIdLength 256 //!< The max number of characters in the unique id a device.
/**
* TTV_WebCamDevice - Information about one specific device instance.
*/
typedef struct
{
utf8char uniqueId[kMaxDeviceIdLength+1]; //!< The unique id of the device which should be saved as a user preference once selected.
utf8char name[kMaxDeviceNameLength+1]; //!< The human readable name of the device.
unsigned int deviceIndex; //!< The device index for the current run of the game. If the device is unplugged and plugged back in it will change.
TTV_WebCamDeviceStatus status; //!< The current capture status.
TTV_WebCamDeviceCapabilityList capabilityList; //!< The list of resolutions and formats the device supports.
} TTV_WebCamDevice;
/**
* TTV_WebCamDeviceList - A list of devices in the system.
*/
typedef struct
{
TTV_WebCamDevice* list; //!< The list.
unsigned int count; //!< The number of elements in the list.
} TTV_WebCamDeviceList;
/**
* TTV_WebCamFrame - Information about a captured frame.
*/
typedef struct
{
uint8_t* imageBuffer; //!< The buffer containing the captured image.
unsigned int deviceIndex; //!< The index of the device from which the frame originated.
unsigned int bufferSize; //!< The length of thr buffer.
TTV_WebCamDeviceCapability capability; //!< The active capability at the time the frame was generated.
} TTV_WebCamFrame;
/**
* TTV_WebCamInitializationCallback - The callback to the client indicated the result of the webcam system initializing. Once this is called
* and indicates success the client will receive device change events which indicate devices being found.
*
* @param error The result code of the initialization. TTV_EC_SUCCESS indicates success.
* @param userdata The custom data provided by the client.
*/
typedef void (*TTV_WebCamInitializationCallback) (TTV_ErrorCode error, void* userdata);
/**
* TTV_WebCamShutdownCallback - The callback to the client indicated the result of the webcam system shutting down. Once this is called the
* webcam system is no longer available until reinitialized.
*
* @param error The result code of the initialization. TTV_EC_SUCCESS indicates success.
* @param userdata The custom data provided by the client.
*/
typedef void (*TTV_WebCamShutdownCallback) (TTV_ErrorCode error, void* userdata);
/**
* TTV_WebCamDeviceStatusCallback - Callback called when a device starts or stops capturing. The device data should be copied before the callback returns if the client
* wants to keep it. If the capability is in a format that the client doesn't know how to handle it should call TTV_WebCam_ConvertToRGBA to convert the buffer
* to RGBA. The status is contained in the device info.
*
* @param device The device info.
* @param capability The capability which was started or stopped.
* @param error Any error associated with the status change. TTV_EC_SUCCESS indicates success.
* @param userdata The custom data provided by the client.
*/
typedef void (*TTV_WebCamDeviceStatusCallback) (const TTV_WebCamDevice* device, const TTV_WebCamDeviceCapability* capability, TTV_ErrorCode error, void* userdata);
/**
* TTV_WebCamDeviceChangeCallback - Callback called when a device is added or removed from the system. The device data should be copied before the callback returns if the client
* wants to keep it.
*
* @param change The type of change.
* @param device The device the change occurred on.
* @param error Any error associated with the status change. TTV_EC_SUCCESS indicates success.
* @param userdata The custom data provided by the client in the TTV_WebCamCallbacks structure during initialization.
*/
typedef void (*TTV_WebCamDeviceChangeCallback) (TTV_WebCamDeviceChange change, const TTV_WebCamDevice* device, TTV_ErrorCode error, void* userdata);
/**
* TTV_WebCamCallbacks - The set of callbacks and their data which are called when unsolicited events
* occur in the webcam system.
*/
typedef struct
{
TTV_WebCamDeviceChangeCallback deviceChangeCallback; //!< The callback to call when a device is found or lost.
void* deviceChangeUserData; //!< The userdata to pass along when deviceChangeCallback is called.
} TTV_WebCamCallbacks;
/**
* TTV_WebCam_Init - Sets up the webcam system for use.
*
* @param interruptCallbacks The structure which configures the callbacks and user data passed along when an unsolicited event occurs.
* @param initCallback The callback which is called when initialization of the systen is complete. When the callback is called the device list will
* be available and devices ready for use.
* @param userdata The data to be passed into the initCallback.
*
* @return TTV_EC_SUCCESS, TTV_EC_ALREADY_INITIALIZED, TTV_EC_INVALID_ARG.
*/
TTV_ErrorCode TTV_WebCam_Init(const TTV_WebCamCallbacks* interruptCallbacks, TTV_WebCamInitializationCallback initCallback, void* userdata);
/**
* TTV_WebCam_Shutdown - Shuts down and cleans up the internals of the webcam system.
*
* @param callback The callback which is called when shutdown of the systen is complete.
* @param userdata The data to be passed into the callback.
*
* @return TTV_EC_SUCCESS, TTV_EC_NOT_INITIALIZED.
*/
TTV_ErrorCode TTV_WebCam_Shutdown(TTV_WebCamShutdownCallback callback, void* userdata);
/**
* TTV_WebCam_Start - Begins capturing from the named device. The unique id of the device can be obtained from a call to TTV_WebCam_GetDevices. The callback will
* be called when the start has been processed. When capturing starts the frameReadyCallback in the configured interruptCallbacks will be
* called periodically with the latest frame from the device.
*
* @param uniqueId The unique identifer of the device which can be found in the TTV_WebCamDevice struct.
* @param capabilityIndex The index of the parameters to use when capturing frames from the device.
* @param callback The callback to call when capturing begins.
* @param userdata The data to pass to the callback.
*
* @return TTV_EC_SUCCESS, TTV_EC_NOT_INITIALIZED.
*/
TTV_ErrorCode TTV_WebCam_Start(int deviceIndex, int capabilityIndex, TTV_WebCamDeviceStatusCallback callback, void* userdata);
/**
* TTV_WebCam_Stop - Stops the capturing of frames from the device. The callback will be called when the start has been processed.
*
* @param uniqueId The unique identifer of the device which can be found in the TTV_WebCamDevice struct.
* @param callback The callback to call when capturing begins.
* @param userdata The data to pass to the callback.
*
* @return TTV_EC_SUCCESS, TTV_EC_NOT_INITIALIZED.
*/
TTV_ErrorCode TTV_WebCam_Stop(int deviceIndex, TTV_WebCamDeviceStatusCallback callback, void* userdata);
/**
* TTV_WebCam_FlushEvents - Causes callbacks from the webcam system to be flushed to the client. This should be called very frequently (once per game frame ideally).
*
* @return TTV_EC_SUCCESS, TTV_EC_NOT_INITIALIZED.
*/
TTV_ErrorCode TTV_WebCam_FlushEvents();
/**
* TTV_WebCam_IsFrameAvailable - Determines if there is a new frame available for the given device.
*
* @param deviceIndex The index of the device to check.
* @param available The result.
*
* @return TTV_EC_SUCCESS, TTV_EC_NOT_INITIALIZED.
*/
TTV_ErrorCode TTV_WebCam_IsFrameAvailable(int deviceIndex, bool* available);
/**
* TTV_WebCam_GetFrame - Fills the given buffer with the contents of the next available frame.
*
* NOTE: On iOS the image is not automatically rotated to compensate for the orientation of the device.
* The provided image is captured from the cameras default orientation of UIDeviceOrientationPortrait.
* Use the following code snippet to determine the device's current orientation and make changes to the way you display it.
*
* UIInterfaceOrientation orient = [[UIApplication sharedApplication] statusBarOrientation];
*
* @param deviceIndex The index of the device to get the image from.
* @param buffer The buffer to fill.
* @param pitch The number of bytes in each row of the buffer.
*
* @return TTV_EC_SUCCESS, TTV_EC_NOT_INITIALIZED.
*/
TTV_ErrorCode TTV_WebCam_GetFrame(int deviceIndex, void* buffer, unsigned int pitch);
#ifdef __cplusplus
}
#endif
#endif /* TTVSDK_TWITCH_WEBCAM_H */