diff --git a/src/libs/pvqa/include/aqua++.h b/src/libs/pvqa/include/aqua++.h new file mode 100644 index 00000000..33dd51bf --- /dev/null +++ b/src/libs/pvqa/include/aqua++.h @@ -0,0 +1,121 @@ +#ifndef _AQUA_CPP_H +#define _AQUA_CPP_H + +#include +#include +#include +#include +#include +#include +#include + +#include "aqua.h" + +namespace sevana +{ + +class aqua +{ +protected: + void* mContext = nullptr; + std::mutex mMutex; + +public: + // Returns 0 (zero) on successful initialization, otherwise it is error code + static int initialize(const std::string& pathToLicenseFile); + static int initialize(const void* buffer, size_t len); + + // Deinitialize library + static void release(); + + // Current version number + static std::string version(); + + aqua(); + ~aqua(); + + // Open library instance + void open(); + + // Close library instance + void close(); + bool is_open() const; + + // Config + typedef std::map config; + void configure_with(const config& config); + static config parse(const std::string& line); + + struct audio_buffer + { + audio_buffer() + {} + + audio_buffer(int size) + { + mData = std::make_shared>(); + mData->resize(size); + } + + audio_buffer(const void* data, int size) + { + mData = std::make_shared>(); + mData->resize(size); + memcpy(mData->data(), data, size); + } + + void* data() + { + return mData ? mData->data() : nullptr; + } + + const void* data() const + { + return mData ? mData->data() : nullptr; + } + + int size() const + { + return mData ? mData->size() : 0; + } + + int mRate = 8000; + int mChannels = 1; + std::shared_ptr> mData; + bool is_initialized() const { return mRate > 0 && mChannels > 0 && mData; } + }; + + + struct faults_report + { + float mSignalAdvancedInMilliseconds = -5000.0; + float mMistimingInPercents = -5000.0; + + struct item + { + std::string mSource, mDegrated, mUnit; + }; + typedef std::map result_map; + result_map mResultMap; + + std::string text() const; + }; + + static faults_report load_report(std::istream& input); + + // Compare in one shot. Report will include text representation of json report. + struct result + { + float mMos = 0.0f, mPercents = 0.0f, mPesqLike = 0.0f; + faults_report mFaults; + + // This can be both plain text or json depending on configuration parameter 'output': 'txt' or 'json' + std::string mFaultsText; + }; + + result compare(audio_buffer& reference, audio_buffer& test); +}; + +} + +#endif diff --git a/src/libs/pvqa/include/aqua.h b/src/libs/pvqa/include/aqua.h new file mode 100644 index 00000000..b9a6422a --- /dev/null +++ b/src/libs/pvqa/include/aqua.h @@ -0,0 +1,174 @@ +#ifndef __A_Qu_A_dll_h__ +#define __A_Qu_A_dll_h__ + +#ifdef _WINDOWS +# if defined(AQUA_STATIC_LIBRARY) +# define SSA_SDK_API extern "C" +# else +# ifdef SSA_HEADERS_EXPORTS +# define SSA_SDK_API extern "C" __declspec(dllexport) +# else +# define SSA_SDK_API extern "C" __declspec(dllimport) +# endif +# endif +#else +# define SSA_SDK_API +#endif + + + + +// The structure containing information about AQuA library +struct TSSA_AQuA_Info +{ + int dStructSize; // Structure size + char * dCopyrightString; // Copyright string + char * dVersionString; // Product name and version number string + int dSampleRateLimit; // Maximal sampling frequency supported by the library + int dChannelsLimit; // Maximal amount of channels supported by the library + bool isDifferentFFmtCheckingEnabled; + // If comparison of audio files in different formats is allowed + const char * pSupportedBitsPerSampleList; + // List of supported sample bits + const char * pSupportedCodecsList; // List of supported audio compression algorithms +}; + +// The structure contains received quality measurement estimations +struct TSSA_AQuA_Results +{ + double dPercent; // Percentage + double dMOSLike; // MOS-like + double dPESQLike; // PESQ-like +}; + +// The structure containing audio data from a single source +struct TSSA_AQuA_AudioItem +{ + long dSampleRate; // Sampling frequency + long dNChannels; // The number of channels in the sound (1 mono, 2 stereo, etc.) + short * pSamples; // The signal samples + long dNSamples; // Number of signal samples +}; + +// The structure contains the audio data for comparison +struct TSSA_AQuA_AudioData +{ + TSSA_AQuA_AudioItem dSrcData; // Data reference signal + TSSA_AQuA_AudioItem dTstData; // These degraded signal +}; + + +// Library initialization, check library copyrights and software license period and validity. +// If initialization is successful the function returns 0, otherwise returns error code. +SSA_SDK_API int SSA_InitLib(char * aPLicFName); +SSA_SDK_API int SSA_InitLibWithData(const void* buffer, size_t len); + +// This function is called when work with the library is finished. +// Invoking this function is important for further work with the library. +SSA_SDK_API void SSA_ReleaseLib(void); + +// Returns pointer to data structure containing information about AQuA library +SSA_SDK_API TSSA_AQuA_Info * SSA_GetPAQuAInfo(void); + + + +// Creates audio analyzer. If successful returns analyzer's handle, +// if unsuccessful the function returns NULL. +SSA_SDK_API void * SSA_CreateAudioQualityAnalyzer(void); + +// Finishes working with analyzer and deletes all variables used during analyzer work. +SSA_SDK_API void SSA_ReleaseAudioQualityAnalyzer(void * anSSA_ID); + +// Performs audio files quality estimation according to the files passed +// to the analyzer in the setting functions. +SSA_SDK_API int SSA_OnTestAudioFiles(void * anSSA_ID); + +// Performs audio quality estimation according to the data passed +// to the analyzer in aSSA_PAudio structure. +SSA_SDK_API int SSA_OnTestAudioData(void * anSSA_ID, TSSA_AQuA_AudioData * aSSA_PAudio); + +// Performs audio quality estimation according to the data passed +// to the analyzer in aSSA_PAudio structure (with accumulation). +SSA_SDK_API int SSA_OnTestAddAudioData(void * anSSA_ID, TSSA_AQuA_AudioData * aSSA_PAudio); + + + +// -------------------------------------------------------------------------------------- +// Checking file formats +// -------------------------------------------------------------------------------------- + +// Checks if file formats are supported by the library. If the format is supported +// the function returns "true", otherwise the return value is "false". +SSA_SDK_API bool SSA_IsFileFormatSupportable(void * anSSA_ID, char * aPFName); + +// Checks if file comparison is possible. If files format is supported and +// file comparison is supported for these file formats then the return value +// is "true", otherwise the function returns "false". +SSA_SDK_API bool SSA_AreFilesComparable(void * anSSA_ID, char * aPSrcFName, char * aPTstFName); + + + +// -------------------------------------------------------------------------------------- +// Displaying audio quality testing results +// -------------------------------------------------------------------------------------- + +// Returns string length containing test results in text. +SSA_SDK_API int SSA_GetQualityStringSize(void * anSSA_ID); + +// Fills string with the text of the test result. User should allocate memory +// for the string by himself. Amount of the memory required can be found +// by function SSA_GetQualityStringSize. +SSA_SDK_API int SSA_FillQualityString(void * anSSA_ID, char * aPString); + +// Fills the structure with results of audio quality measurements. +SSA_SDK_API int SSA_FillQualityResultsStruct(void * anSSA_ID, TSSA_AQuA_Results * aPQResults); + +// Returns size of array for integral energy spectrum of the original signal. +// Note that signal spectrum is available only after quality estimation has been performed +// and only in the mode "QualityMode" = 0. If signal spectrum was not calculated +// the function returns 0, in case of error the function returns -1. +SSA_SDK_API int SSA_GetSrcSignalSpecSize(void * anSSA_ID); + +// Returns size of array for integral energy spectrum of the signal under test. +// Note that signal spectrum is available only after quality estimation has been performed +// and only in the mode "QualityMode" = 0. If signal spectrum was not calculated +// the function returns 0, in case of error the function returns -1. +SSA_SDK_API int SSA_GetTstSignalSpecSize(void * anSSA_ID); + +// Fills array with integral energy spectrum of the original signal. +// Note that signal spectrum is available only after quality estimation has been performed +// and only in the mode "QualityMode" = 0. If signal spectrum was not calculated +// the function returns 0, in case of error the function returns -1. +SSA_SDK_API int SSA_FillSrcSignalSpecArray(void * anSSA_ID, float * aPSpecArray); + +// Fills array with integral energy spectrum of the signal under test. +// Note that signal spectrum is available only after quality estimation has been performed +// and only in the mode "QualityMode" = 0. If signal spectrum was not calculated +// the function returns 0, in case of error the function returns -1. +SSA_SDK_API int SSA_FillTstSignalSpecArray(void * anSSA_ID, float * aPSpecArray); + +// Returns size of the string containing reasons for quality loss. +// String size does not consider 0 symbol in the end of the string. +SSA_SDK_API int SSA_GetFaultsAnalysisStringSize(void * anSSA_ID); + +// Fills string with reasons for audio quality loss. String aPString contains only +// meaningful symbols and does not contain 0 symbol in the end. +SSA_SDK_API int SSA_FillFaultsAnalysisString(void * anSSA_ID, char * aPString); + +// Returns size of the string containing signals spectrums pairs. +SSA_SDK_API int SSA_GetSpecPairsStringSize(void * anSSA_ID); + +// Fills string with signals spectrums pairs. +SSA_SDK_API int SSA_FillSpecPairsString(void * anSSA_ID, char * aPString, int aSSize); + +SSA_SDK_API int SSA_GetSpecPairsSize(void * anSSA_ID); +SSA_SDK_API int SSA_GetSpecPairsArray(void * anSSA_ID, float * aPArray); + +// Sets any parameter of the analyzer +SSA_SDK_API bool SSA_SetAnyString(void * anSSA_ID, char * aPParName, char * aPParValue); + +// +SSA_SDK_API int SSA_OnHSMGenerate(void * anSSA_ID, bool aFmtID); + +#endif // __A_Qu_A_dll_h__ + diff --git a/src/libs/pvqa/include/pvqa++.h b/src/libs/pvqa/include/pvqa++.h new file mode 100644 index 00000000..44193643 --- /dev/null +++ b/src/libs/pvqa/include/pvqa++.h @@ -0,0 +1,178 @@ +#ifndef _SEVANA_MOS_H +#define _SEVANA_MOS_H + +#include +#include +#include +#include +#include +#include +#include + +# include "pvqa.h" +# if !defined(PVQA_INTERVAL) +# define PVQA_INTERVAL (0.68) +# endif + +namespace sevana { + +enum +{ + pvqa_success = 0, + pvqa_bad_config = 1, + pvqa_not_initialized = 1000, + pvqa_too_much_streams = 1001, + pvqa_no_context = 1002 +}; + +class detector_report +{ +public: + detector_report(); + detector_report(const std::string& report); + ~detector_report(); + + // Detector names + const std::vector& names() const; + + enum status + { + status_ok, + status_poor, + status_uncertain + }; + + // Row for single time interval + struct row + { + float mStart = 0.0f, mEnd = 0.0f; + std::vector mData; + status mStatus; + }; + + // All rows + const std::vector& rows() const; + + // Find difference in impairements + detector_report get_changes(const detector_report& reference); + + // Get short report + std::string to_string() const; + + enum display_options + { + show_regular, + show_difference + }; + + std::string to_table(display_options options = show_regular, const char delimiter = ';') const; + std::string to_json(display_options options = show_regular, bool dedicated_time_fields = true) const; + + // Find number of impairements for whole report + size_t count_of(const std::string& detector_name) const; + +private: + std::vector mRows; + std::vector mDetectorNames; +}; + +class pvqa +{ +private: + static void* mLibraryConfiguration; + static int mLibraryErrorCode; + static std::atomic_int mInstanceCounter; + static std::atomic_uint_least64_t mAllProcessedMilliseconds; + static bool mPvqaLoaded; + + void* mContext = nullptr; + double mIntervalLength = 0.68; + size_t mProcessedSamples = 0, + mProcessedMilliseconds = 0; + + bool mAudioLineInitialized = false; + std::string mDumpWavPath; + int mErrorCode = 0; + size_t mRate = 0, mChannels = 1; + +public: + static std::string version(); + static std::string mos_to_color(float mos); + struct DetectorsList + { + std::vector mNames; + int mStartIndex = 0; + }; + + static DetectorsList detectors_names(const std::string& report); + +#if defined(TARGET_ANDROID) + // Required to call before any call to SevanaPVQA instance methods + static void setupAndroidEnvironment(void* environment, void* appcontext); +#endif + + // Path to config file can be empty + // In this case library will be considered initialized (but will produce zero MOS) + static bool initialize(const std::string& pathToLicenseFile, const std::string& pathToConfigFile); + static bool initialize(const void* license_buffer, size_t license_len, + const void* config_buffer, size_t config_len); + static bool is_initialized(); + + static int library_error(); + static void release(); + static int instance_counter() { return mInstanceCounter; } + static uint64_t processed_milliseconds() { return mAllProcessedMilliseconds; } + + enum class Codec + { + None, + G711, + ILBC, + G722, + G729, + GSM, + AMRNB, + AMRWB, + OPUS + }; + static float max_mos(Codec c); + + pvqa(); + ~pvqa(); + + bool open(size_t rate, size_t channels, double interval = 0.680); + void close(); + bool is_open() const; + + // Update/Get model. pcm_length is bytes. + bool update(const void* pcm_buffer, size_t pcm_length); + int error() const; + + typedef std::vector> echo_data; + struct result + { + float mMos = 0.0f; + std::string mReport; + size_t mIntervals = 0, mPoorIntervals = 0; + }; + + bool get_result(result& r, size_t last_milliseconds = 0); + struct detector_data + { + // Names corresponding to mData array + std::vector mNames; + + // Zero element in every row is time offset (in milliseconds) + std::vector> mData; + }; + + detector_data get_detector(const std::string& name, float start_time, float end_time); + echo_data get_echo(); + + // Combines update & get_result calls + bool singleshot(result& r, const void* pcm_buffer, size_t pcm_length); +}; + +} // end of namespace + +#endif diff --git a/src/libs/pvqa/include/pvqa.h b/src/libs/pvqa/include/pvqa.h new file mode 100644 index 00000000..ef9df4ab --- /dev/null +++ b/src/libs/pvqa/include/pvqa.h @@ -0,0 +1,155 @@ +#ifndef __P_V_Q_A_dll_h__ +#define __P_V_Q_A_dll_h__ + +#ifdef _WINDOWS +#if defined(PVQA_STATIC_LIBRARY) +# define PVQA_API extern "C" +#else +# ifdef PVQADLL_EXPORTS + #define PVQA_API extern "C" __declspec(dllexport) +# else + #define PVQA_API extern "C" __declspec(dllimport) +# endif +#endif +#else +# if defined(__cplusplus) +# define PVQA_API extern "C" +# else +# define PVQA_API extern +# endif +#endif + +// It is for size_t type +#include + +// The structure contains received quality measurement estimations +typedef struct +{ + double dMOSLike; // MOS-like + + long dNumPoorIntervals; + long dNumTotalIntervals; + + double dTimeShift; +} TPVQA_Results; + +// +typedef struct +{ + long dSampleRate; // Sample rate of signal + long dNChannels; // Number of sound channels in audio + short * pSamples; // Pointer to the samples of signal + long dNSamples; // Number of samples +} TPVQA_AudioItem; + +#if defined(__ANDROID__) +// Init Android related part. System info and JNI environment context sometimes has to be initialized in separate from other calls. +PVQA_API void PVQA_SetupAndroidEnvironment(void* /* JNIEnv* inside */environment, void* /* jobject */ appcontext); +#endif + +// Library initialization, check library copyrights and software license period and validity. +// If initialization is successful the function returns 0, otherwise returns error code. +PVQA_API int PVQA_InitLib(const char * aPLicFName); +PVQA_API int PVQA_InitLibWithLicData(const void* buffer, size_t length); + +// Returns a string with the name +PVQA_API const char * PVQA_GetName(void); + +// Returns a string with the version number +PVQA_API const char * PVQA_GetVersion(void); + +// Returns a string with the copyright +PVQA_API const char * PVQA_GetCopyrightString(void); + +// This function is called when work with the library is finished. +// Invoking this function is important for further work with the library. +PVQA_API void PVQA_ReleaseLib(void); + +// Creates audio analyzer. If successful returns analyzer's handle, +// if unsuccessful the function returns NULL. +PVQA_API void * PVQA_CreateAudioQualityAnalyzer(void * aCFG_ID); + +// Finishes working with analyzer and deletes all variables used during analyzer work. +PVQA_API int PVQA_ReleaseAudioQualityAnalyzer(void * aPVQA_ID); + +// Set length of samples delay line +PVQA_API int PVQA_AudioQualityAnalyzerSetIntervalLength(void * aPVQA_ID, double length); + +// Create audio-processing delay-line +PVQA_API int PVQA_AudioQualityAnalyzerCreateDelayLine(void * aPVQA_ID, long aSampleRate, long aNChannels, double aLineTime); + +// Start recording a debug sound file +PVQA_API int PVQA_StartRecordingWave(void * aPVQA_ID, const char * aPWavFName, long aSampleRate, long aNChannels); + +// Performs audio file quality estimation +PVQA_API int PVQA_OnTestAudioFile(void * aPVQA_ID, const char * aPFileName); + +// Process loaded in memory audio data +PVQA_API int PVQA_OnTestAudioData(void * aPVQA_ID, TPVQA_AudioItem * aPVQA_PAudio); + +// Put Audio data to delay-line and process it +PVQA_API int PVQA_OnTestAddAudioData(void * aPVQA_ID, TPVQA_AudioItem * aPVQA_PAudio); + +// Start audio-stream processing +PVQA_API int PVQA_OnStartStreamData(void * aPVQA_ID); + +// Process streaming Audio data +PVQA_API int PVQA_OnAddStreamAudioData(void * aPVQA_ID, TPVQA_AudioItem * aPVQA_PAudio); +PVQA_API int PVQA_OnAddStreamAudioDataHex(void * aPVQA_ID, int rate, int channels, const char* samples); + +// Updates quality results data +PVQA_API int PVQA_OnUpdateStreamQualityResults(void * aPVQA_ID, int rate, int millisecondsFromEnd); + +// Finalize quality measurements at this moment (not finalize stream processing) +PVQA_API int PVQA_OnFinalizeStream(void * aPVQA_ID, long aSampleRate); + + + +// -------------------------------------------------------------------------------------- +// Displaying audio quality testing results +// -------------------------------------------------------------------------------------- + +// Returns string length containing test results in text. +PVQA_API int PVQA_GetQualityStringSize(void * anPVQA_ID); + +// Fills string with the text of the test result. User should allocate memory +// for the string by himself. Amount of the memory required can be found +// by function PVQA_GetQualityStringSize. +PVQA_API int PVQA_FillQualityString(void * aPVQA_ID, char * aPString); + +// Returns string by combining PVQA_GetQualityStringSize() + PVQA_FillQualityString() + PVQA_FillQualityResultsStruct() +PVQA_API char* PVQA_GetQualityString(void * ctx, double* mos, int* errCode); + +// Fills the structure with results of audio quality measurements. +PVQA_API int PVQA_FillQualityResultsStruct(void * aPVQA_ID, TPVQA_Results * aPQResults); + +// Get a list of the names of the values of the detector +// No need to free() the pointer. +PVQA_API const char ** PVQA_GetProcessorValuesNamesList(void * aPVQA_ID, const char * aPDetectorName, int * errCode); + +typedef struct +{ + int columns, rows; + float* data; +} PVQA_Array2D; + +// Get a list of the values of the detector +// Returned value has to be released via PVQA_ReleaseArray2D +PVQA_API PVQA_Array2D* PVQA_GetProcessorValuesList(void * aPVQA_ID, const char * aPDetectorName, long aStartTime, + long aStopTime, const char * aStatType, int * errCode); +// Release allocated 2D array +PVQA_API void PVQA_ReleaseArray2D(PVQA_Array2D* array); + +// -------------------------------------------------------------------------------------- +// Working with configuration files +// -------------------------------------------------------------------------------------- + +// Load settings File in memory +PVQA_API void * PVQA_LoadCFGFile(const char * aFileName, int * errCode); +PVQA_API void * PVQA_LoadCFGData(const void* buffer, size_t length, int* errCode); + +// Release settings file structures +PVQA_API int PVQA_ReleaseCFGFile(void * aCFG_ID); + +#endif // __P_V_Q_A_dll_h__ +