Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creating nested TLV8 structures #79

Open
nanosonde opened this issue Dec 16, 2020 · 2 comments
Open

Creating nested TLV8 structures #79

nanosonde opened this issue Dec 16, 2020 · 2 comments

Comments

@nanosonde
Copy link

nanosonde commented Dec 16, 2020

Is there any example on how to easily create nested TLV8 structures with the given API?

Maybe similiar to this implementation?
https://github.com/maximkulkin/esp32-homekit-camera/blob/261363ce0a9e0a561a1804213294a24737881480/main/accessory.c#L695-L711

@nanosonde
Copy link
Author

nanosonde commented Dec 16, 2020

This is an incomplete example which shows how I could do it.
Is this correct? How could I improve the .valueOffset calculation?

UPDATE:
Got it working. I was not aware of the C builtin command offsetof() after all those years. 😄
This makes the offset calculation a lot better.

bool isValid(void *unsused HAP_UNUSED)
{
    return true;
}

typedef struct
{
    struct
    {
        uint8_t videoCodecType;
        struct
        {
            uint8_t profileID;
            uint8_t level;
            uint8_t packetizationMode;
        } videoCodecParams;
    } videoConfigCodec;
} supportedVideoConfigStruct;

supportedVideoConfigStruct supportedVideoConfigValue =
{
    {
        .videoCodecType = 0,
        {
            .profileID = 0,
            .level = 0,
            .packetizationMode = 0
        }
    }
};

HAP_STRUCT_TLV_SUPPORT(void, supportedVideoConfigFormat)
HAP_STRUCT_TLV_SUPPORT(void, videoCodecConfigFormat)
HAP_STRUCT_TLV_SUPPORT(void, videoCodecParamsFormat)
HAP_STRUCT_TLV_SUPPORT(void, videoAttributesFormat)

const HAPUInt8TLVFormat videoCodecParamsProfileID = {
    .type = kHAPTLVFormatType_UInt8,
    .constraints = { .minimumValue = 0, .maximumValue = 2},
    .callbacks = { .getDescription = NULL }
};
const HAPStructTLVMember videoCodecParamsProfileIDMember = {
    .valueOffset = offsetof(supportedVideoConfigStruct, videoConfigCodec.videoCodecParams.profileID),
    .isSetOffset = 0,
    .tlvType = 1,
    .debugDescription = "Video Config Config Params Profile ID",
    .format = &videoCodecParamsProfileID,
    .isOptional = false,
    .isFlat = false
};

const HAPUInt8TLVFormat videoCodecParamsLevel = {
    .type = kHAPTLVFormatType_UInt8,
    .constraints = { .minimumValue = 0, .maximumValue = 2},
    .callbacks = { .getDescription = NULL }
};
const HAPStructTLVMember videoCodecParamsLevelMember = {
    .valueOffset = offsetof(supportedVideoConfigStruct, videoConfigCodec.videoCodecParams.level),
    .isSetOffset = 0,
    .tlvType = 2,
    .debugDescription = "Video Config Config Params Level",
    .format = &videoCodecParamsLevel,
    .isOptional = false,
    .isFlat = false
};

const HAPUInt8TLVFormat videoCodecParamsPacketizationMode = {
    .type = kHAPTLVFormatType_UInt8,
    .constraints = { .minimumValue = 0, .maximumValue = 2},
    .callbacks = { .getDescription = NULL }
};
const HAPStructTLVMember videoCodecParamsPacketizationModeMember = {
    .valueOffset = offsetof(supportedVideoConfigStruct, videoConfigCodec.videoCodecParams.packetizationMode),
    .isSetOffset = 0,
    .tlvType = 3,
    .debugDescription = "Video Config Config Packetization Mode",
    .format = &videoCodecParamsPacketizationMode,
    .isOptional = false,
    .isFlat = false
};

/* ---------------------------------------------------------------------------------------------*/

const HAPUInt8TLVFormat videoCodecType = {
    .type = kHAPTLVFormatType_UInt8,
    .constraints = { .minimumValue = 0, .maximumValue = 1},
    .callbacks = { .getDescription = NULL }
};
const HAPStructTLVMember videoCodecTypeMember = {
    .valueOffset = offsetof(supportedVideoConfigStruct, videoConfigCodec.videoCodecType),
    .isSetOffset = 0,
    .tlvType = 1,
    .debugDescription = "Video Codec Type",
    .format = &videoCodecType,
    .isOptional = false,
    .isFlat = false
};


const videoCodecConfigFormat videoCodecParams = {
    .type = kHAPTLVFormatType_Struct,
    .members = (const HAPStructTLVMember* const[]) { &videoCodecParamsProfileIDMember,
                                                     &videoCodecParamsLevelMember,
                                                     &videoCodecParamsPacketizationModeMember,
                                                     NULL},
    .callbacks = { .isValid = isValid }
};
const HAPStructTLVMember videoCodecParamsMember = {
    .valueOffset = offsetof(supportedVideoConfigStruct, videoConfigCodec.videoCodecParams),
    .isSetOffset = 0,
    .tlvType = 2,
    .debugDescription = "Video Codec Parameters",
    .format = &videoCodecParams,
    .isOptional = false,
    .isFlat = false
};

const videoCodecConfigFormat videoCodecConfig = {
    .type = kHAPTLVFormatType_Struct,
    .members = (const HAPStructTLVMember* const[]) { &videoCodecTypeMember,
                                                     &videoCodecParamsMember,
                                                     NULL},
    .callbacks = { .isValid = isValid }
};
const HAPStructTLVMember videoCodecConfigMember = {
    .valueOffset = offsetof(supportedVideoConfigStruct, videoConfigCodec),
    .isSetOffset = 0,
    .tlvType = 1,
    .debugDescription = "Video Config Config",
    .format = &videoCodecConfig,
    .isOptional = false,
    .isFlat = false
};

const supportedVideoConfigFormat supported_video_config = {
    .type = kHAPTLVFormatType_Struct,
    .members = (const HAPStructTLVMember* const[]) { &videoCodecConfigMember, NULL},
    .callbacks = { .isValid = isValid }
};

/**
 * Handle read request to the 'SupportedVideoStreamConfiguration' characteristic of the Camera RTP Stream Management service.
 */
HAP_RESULT_USE_CHECK
HAPError HandleSupportedVideoStreamConfigurationRead(
        HAPAccessoryServerRef* server HAP_UNUSED,
        const HAPTLV8CharacteristicReadRequest* request HAP_UNUSED,
        HAPTLVWriterRef* responseWriter,
        void* _Nullable context HAP_UNUSED) {
    HAPPrecondition(responseWriter);

    HAPLogInfo(&kHAPLog_Default, "%s", __func__);

    HAPError err;

    err = HAPTLVWriterEncode(responseWriter, &supported_video_config, &supportedVideoConfigValue);
    if (err) {
        HAPAssert(err == kHAPError_OutOfResources);
        return err;
    }

    return kHAPError_None;
}

Of course there are more things missing. The attributes and so on.
But at least it shows how to create nested TLV8 structures from C structs.

@joebelford
Copy link
Contributor

Have you expanded on this any more to include an array of structs possibly? I'm working through something similar but trying to support multiple ".videoAttributes".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants