1

I have a native library and what I'm trying to do is to write a .NET Core wrapper to this native library.

On the native side i have an event called OnSpeechEnded :

virtual void OnSpeechEnded(SpeechEndInfo seInfo) = 0;

and native struct SpeechEndInfo has the following structure:

struct SpeechEndInfo
{
    std::vector<AudioData> UntouchedData;
    std::vector<AudioData> AudioAfterPostSpeechUntilSilenceTrigger;
};

Corresponding .NET Standard Class:

 public struct SpeechEndedInfo
    {
        public SpeechEndedInfo(short[] untouchedData, short[] audioAfterPostSpeechUntilSilenceTrigger)
        {
            UntouchedData = new short[untouchedData.Length];
            untouchedData.CopyTo(UntouchedData, 0);


            AudioAfterPostSpeechUntilSilenceTrigger = new short[audioAfterPostSpeechUntilSilenceTrigger.Length];
            audioAfterPostSpeechUntilSilenceTrigger.CopyTo(AudioAfterPostSpeechUntilSilenceTrigger, 0);


        }

        public short[] UntouchedData { get; set; }
        public short[] AudioAfterPostSpeechUntilSilenceTrigger { get; set; }
    };

On .NET Standard side, the following delegate is defined:

delegate void OnSpeechEndedInter(
            [In, MarshalAs(UnmanagedType.LPArray)] short[] untouched, 
            int untouchedSize, 
            [In, MarshalAs(UnmanagedType.LPArray)] short[] audioAfterPostSpeechUntilSilenceTrigger,
            int audioAfterPostSpeechUntilSilenceTriggerSize);

Declaring pinvoke:

[DllImport("VadLite.Pinvokable.dll", CallingConvention = CallingConvention.Cdecl)]
        private static extern void RegisterToSpeechEndedEvent(IntPtr parameters, [MarshalAs(UnmanagedType.FunctionPtr)]OnSpeechEndedInter onSpeechEndedInter);

Declaring _onSpeechEndedInter:

 private OnSpeechEndedInter _onSpeechEndedInter;

Assigning a method to the event:

 _onSpeechEndedInter = invokedMethod;

...

void invokedMethod(short[] untouchedData, 
            int untouchedSize, 
            short[] audioAfterPostSpeechUntilSilenceTrigger,
            int audioAfterPostSpeechUntilSilenceTriggerSize)
        {
            OnSpeechEnded?.Invoke(new SpeechEndedInfo(untouchedData, audioAfterPostSpeechUntilSilenceTrigger));
        }

Finally, the code where native arrays are sent:

RegisterToSpeechEndedEvent(
        void * possiblyOperations,
        void __stdcall onSpeechEndedListener(const int16_t* pUntouchedData, int pUntouchedDataSize, const int16_t *vAudioAfterPostSpeechUntilSilenceTrigger, int vAudioAfterPostSpeechUntilSilenceTriggerSize))
    {

        auto op = (OperationParameters *)possiblyOperations;
        op->OnSpeechEnded([onSpeechEndedListener](SpeechEndInfo ssInfo) {


            std::vector<int16_t> untouchedData;
            std::vector<int16_t> audioAfterPostSpeechUntilSilenceTrigger;

            for (auto & audioData : ssInfo.UntouchedData)
            {
                untouchedData.insert(untouchedData.end(), audioData.Samples, audioData.Samples + audioData.SampleCount);
            }


            for (auto & audioData : ssInfo.AudioAfterPostSpeechUntilSilenceTrigger)
            {
                audioAfterPostSpeechUntilSilenceTrigger.insert(audioAfterPostSpeechUntilSilenceTrigger.end(), audioData.Samples, audioData.Samples + audioData.SampleCount);
            }



            onSpeechEndedListener(untouchedData.empty() ? nullptr : untouchedData.data(),
                    (int)untouchedData.size(),
                    audioAfterPostSpeechUntilSilenceTrigger.empty() ? nullptr : audioAfterPostSpeechUntilSilenceTrigger.data(),
                    (int)audioAfterPostSpeechUntilSilenceTrigger.size());

        });

After running the test program and getting meaningful array sizes on the native side, C# arrays UntouchedData and AudioAfterPostSpeechUntilSilenceTrigger always seem to have size 1.

Probably there is a detail I have missed. I can provide further detail if it is required. Thanks.

1 Answer 1

1

Great!, Finally I have found out the problem. In the delegate declaration, I just had to introduce parameter SizeParamIndex :

delegate void OnSpeechEndedInter(
            [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] short[] untouched, 
            int untouchedSize, 
            [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] short[] audioAfterPostSpeechUntilSilenceTrigger,
            int audioAfterPostSpeechUntilSilenceTriggerSize);

Because the marshaler cannot determine the size of an unmanaged array, we have to pass it in as a separate parameter considering the signature of the method and zero based indexing.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.