Logo

Docy

Custom Logging Tutorial

Estimated reading: 5 minutes

The Immersitech SDK provides a built-in way to override how Immersitech log messages are handled. By default, Immersitech log messages just print the error message to the standard output. But what if you want these messages to log to a file, or print to a user interface for easier debugging? Here’s how you can do just that.

Default Logger

Here we have an example C++ file, log_tutorial.cpp that simply enables Immersitech logging, sets up a room, and adds some participants.

#include <iostream>
#include "immersitech.h"
#include "immersitech_logger.h"

// some constants
#define OUTPUT_SAMPLING_RATE 48000
#define OUTPUT_NUM_FRAMES 480
#define OUTPUT_NUM_CHANNELS 1
#define INTERLEAVED true
#define SPATIAL_QUALITY 1

int main() {
    // set up logging
    imm_enable_logging(true);
    imm_set_log_level(IMM_LOG_DEBUG);

    // initialize the library
    imm_error_code error_code;
    imm_library_configuration output_config = {
        OUTPUT_SAMPLING_RATE,
        OUTPUT_NUM_FRAMES,
        OUTPUT_NUM_CHANNELS,
        INTERLEAVED,
        SPATIAL_QUALITY
    };
    imm_handle imm = imm_initialize_library("Immersitech_Engineering_sound_manager_license_key.dat", NULL, NULL, output_config, &error_code);
    
    // create a room and add some participants
    int room_id = 0;
    imm_create_room(imm, room_id);
    imm_participant_configuration input_config = { 16000, 1, IMM_PARTICIPANT_REGULAR };
    imm_add_participant(imm, room_id, 1, "participant_1", input_config);
    imm_add_participant(imm, room_id, 2, "participant_2", input_config);
    
    return 0;
}

We can compile this and run it on a Mac like so (assuming the Immersitech library, immersitech.h, and immersitech_logging.h are in /usr/local/lib/immersitech):

g++ ./log_tutorial.cpp -I/usr/local/lib/immersitech -L/usr/local/lib/immersitech -limmersitech -Xlinker -rpath -Xlinker /usr/local/lib/immersitech
./a.out

And the output from the default logger should look like this:

[Immersitech] [Tue, 18.04.2023 10:05:28] [ERROR]: The library will work properly except imm_enable_websockets and imm_send_custom_websocket_event.
[Immersitech] [Tue, 18.04.2023 10:05:29] [INFO]: A new room with id 0 was created
[Immersitech] [Tue, 18.04.2023 10:05:29] [DEBUG]: Noise cancellation model: DFN (created)
[Immersitech] [Tue, 18.04.2023 10:05:29] [INFO]: A new participant with id 1 has been added to room 0
[Immersitech] [Tue, 18.04.2023 10:05:29] [DEBUG]: Noise cancellation model: DFN (created)
[Immersitech] [Tue, 18.04.2023 10:05:29] [INFO]: A new participant with id 2 has been added to room 0

Custom Logging

To override the default logger, we’ll need to create a class that inherits the public members of the imm_logger_handler. Then we’ll add a “handle” method that takes in an imm_log_level and a const char*, like so:

class custom_logger : public imm_logger_handler {
public:
    custom_logger(){ };
    ~custom_logger(){ };
    void handle(imm_log_level level, const char *message) {
        std::cout << "---" << imm_logger::to_string(level) << "---" << message << std::endl;
    }
};

For this example, we’re just changing the output formatting of the log messages, but you can do whatever you’d like with the message.

NOTE: You don’t need to handle only displaying messages of a certain log level in this function. The function imm_set_log_level() already does this for you before calling your custom logger handler.

Now, in our main function, we just need to create an instance of this class and initialize it as the logger using these two lines:

custom_logger log;
IMM_LOGGER->initialize(&log);

So the final version of the file will look like this:

#include <iostream>
#include "immersitech.h"
#include "immersitech_logger.h"

#define OUTPUT_SAMPLING_RATE 48000
#define OUTPUT_NUM_FRAMES 480
#define OUTPUT_NUM_CHANNELS 1
#define INTERLEAVED true
#define SPATIAL_QUALITY 1

class custom_logger : public imm_logger_handler {
public:
    custom_logger(){ };
    ~custom_logger(){ };
    void handle(imm_log_level level, const char *message) {
        std::cout << "---" << imm_logger::to_string(level) << "---" << message << std::endl;
    }
};

int main() {
    imm_enable_logging(true);
    imm_set_log_level(IMM_LOG_DEBUG);
    custom_logger log;
    IMM_LOGGER->initialize(&log);
    imm_error_code error_code;
    imm_library_configuration output_config = {
        OUTPUT_SAMPLING_RATE,
        OUTPUT_NUM_FRAMES,
        OUTPUT_NUM_CHANNELS,
        INTERLEAVED,
        SPATIAL_QUALITY
    };
    imm_handle imm = imm_initialize_library("Immersitech_Engineering_sound_manager_license_key.dat", NULL, NULL, output_config, &error_code);
    
    int room_id = 0;
    imm_create_room(imm, room_id);
    imm_participant_configuration input_config = { 16000, 1, IMM_PARTICIPANT_REGULAR };
    imm_add_participant(imm, room_id, 1, "participant_1", input_config);
    imm_add_participant(imm, room_id, 2, "participant_2", input_config);
    
    return 0;
}

That’s it! Now, whenever the Immersitech library logs an error message, this new method will be called. When we run it, we’ll now see this output.

---ERROR---The library will work properly except imm_enable_websockets and imm_send_custom_websocket_event.
---INFO---A new room with id 0 was created
---DEBUG---Noise cancellation model: DFN (created)
---INFO---A new participant with id 1 has been added to room 0
---DEBUG---Noise cancellation model: DFN (created)
---INFO---A new participant with id 2 has been added to room 0

Please feel free to use this method to throw your debug messages wherever they’re most convenient for you. And as always, reach out to us if you have any further difficulties or questions. Happy debugging!

CONTENTS