pothosware / SoapyRTLSDR

SoapySDR RTL-SDR Support Module
https://github.com/pothosware/SoapyRTLSDR/wiki
MIT License
137 stars 31 forks source link

Access Violation in SoapyRTLSDR on Windows 11 (PothosSDR installation) for Consecutive Runs #76

Open KeyserSoze-ND opened 2 months ago

KeyserSoze-ND commented 2 months ago

I'm encountering a Windows fatal exception: access violation errorwhen using SoapyRTLSDR on Windows 11 Home 64-bit. The crash occurs when trying to interact with the RTL-SDR device (NooElec R820T2 SDR & DVB-T) using SoapySDR, and it seems to be a bug in the SoapyRTLSDR implementation on Windows.

The crash happens silently, but after adding the Python faulthandlerlibrary, I was able to trace the exact point of failure.

Environment:

SoapySDRUtil output:

C:\PothosSDR>SoapySDRUtil --info
######################################################
##     Soapy SDR -- the SDR abstraction library     ##
######################################################

Lib Version: v0.8.1-PothosSDR-2021.07.25-vc16-x64
API Version: v0.8.0
ABI Version: v0.8
Install root: C:\PothosSDR
Search path:  C:\PothosSDR/lib/SoapySDR/modules0.8
Module found: C:\PothosSDR/lib/SoapySDR/modules0.8/airspyhfSupport.dll (0.2.0-d682533)
Module found: C:\PothosSDR/lib/SoapySDR/modules0.8/airspySupport.dll   (0.2.0-411f73e)
Module found: C:\PothosSDR/lib/SoapySDR/modules0.8/audioSupport.dll    (0.1.1-91080cb)
Module found: C:\PothosSDR/lib/SoapySDR/modules0.8/bladeRFSupport.dll  (0.4.1-70505a5)
Module found: C:\PothosSDR/lib/SoapySDR/modules0.8/HackRFSupport.dll   (0.3.3-8d2e7be)
Module found: C:\PothosSDR/lib/SoapySDR/modules0.8/IrisSupport.dll     (2020.02.0.1-f100723)
Module found: C:\PothosSDR/lib/SoapySDR/modules0.8/LMS7Support.dll     (20.10.0-a45e482d)
Module found: C:\PothosSDR/lib/SoapySDR/modules0.8/miriSupport.dll     (0.2.6-585c012)
Module found: C:\PothosSDR/lib/SoapySDR/modules0.8/netSDRSupport.dll   (0.1.0-51516db)
Module found: C:\PothosSDR/lib/SoapySDR/modules0.8/osmosdrSupport.dll  (0.2.6-585c012)
Module found: C:\PothosSDR/lib/SoapySDR/modules0.8/RedPitaya.dll       (0.1.1-3d576f8)
Module found: C:\PothosSDR/lib/SoapySDR/modules0.8/remoteSupport.dll   (0.6.0-c09b2f1)
Module found: C:\PothosSDR/lib/SoapySDR/modules0.8/rtlsdrSupport.dll   (0.3.2-53ee8f4)
Module found: C:\PothosSDR/lib/SoapySDR/modules0.8/sdrPlaySupport.dll  (0.3.0-206b241)
Module found: C:\PothosSDR/lib/SoapySDR/modules0.8/uhdSupport.dll      (0.4.1-9a738c3)
Module found: C:\PothosSDR/lib/SoapySDR/modules0.8/volkConverters.dll[WARNING] SoapyVOLKConverters: no VOLK config file found. Run volk_profile for best performance.
  (0.1.0-62ac7f5)
Available factories... airspy, airspyhf, audio, bladerf, hackrf, iris, lime, miri, netsdr, osmosdr, redpitaya, remote, rtlsdr, sdrplay, uhd
Available converters...
 -  CF32 -> [CF32, CF64, CS16, CS32, CS8, CU16, CU8]
 -  CF64 -> [CF32, CS16, CS32, CS8]
 -  CS16 -> [CF32, CF64, CS16, CS8, CU16, CU8]
 -  CS32 -> [CF32, CF64, CS32]
 -   CS8 -> [CF32, CF64, CS16, CS8, CU16, CU8]
 -  CU16 -> [CF32, CS16, CS8]
 -   CU8 -> [CF32, CS16, CS8]
 -   F32 -> [F32, F64, S16, S32, S8, U16, U8]
 -   F64 -> [F32, S16, S32, S8]
 -   S16 -> [F32, F64, S16, S8, U16, U8]
 -   S32 -> [F32, F64, S32]
 -    S8 -> [F32, F64, S16, S8, U16, U8]
 -   U16 -> [F32, S16, S8]
 -    U8 -> [F32, S16, S8]

The following python script can be used to reproduce the error:

import os
import ctypes
os.add_dll_directory(r'C:\PothosSDR\bin') # 
ctypes.windll.LoadLibrary(r'C:\PothosSDR\\bin\rtlsdr.dll') # 
import SoapySDR
import time
import faulthandler
faulthandler.enable()

def main():  
    args = {'driver': 'rtlsdr'}  
    sdr = SoapySDR.Device(args)
    sdr.setSampleRate(SoapySDR.SOAPY_SDR_RX, 0, 2.048e6)
    sdr.setFrequency(SoapySDR.SOAPY_SDR_RX, 0, 100e6)    
    stream = sdr.setupStream(SoapySDR.SOAPY_SDR_RX, SoapySDR.SOAPY_SDR_CF32)
    sdr.activateStream(stream)
    time.sleep(1) 
    sdr.deactivateStream(stream)
    sdr.closeStream(stream)
    print("Stream closed")
    time.sleep(1)

if __name__ == "__main__":    
    while True:
        main()

Expected behaviour: The program should run without crashing, and the SDR device should be properly deactivated and closed at each iteration.

Actual behaviour: The program crashes with a "Windows fatal exception: access violation error" in the SoapySDR.py library when closing the stream and cleaning up the SDR device. Here is the error traceback captured using faulthandler:

[WARNING] SoapyVOLKConverters: no VOLK config file found. Run volk_profile for best performance.
Found Rafael Micro R820T/2 tuner
[INFO] Opening Generic RTL2832U OEM :: df47a2b4edae...
Found Rafael Micro R820T/2 tuner
[INFO] Using format CF32.
Allocating 15 (non-zero-copy) user-space buffers
Stream closed
[INFO] Opening Generic RTL2832U OEM :: df47a2b4edae...
Found Rafael Micro R820T/2 tuner
[INFO] Using format CF32.
Allocating 15 (non-zero-copy) user-space buffers
Stream closed
[INFO] Opening Generic RTL2832U OEM :: df47a2b4edae...
Found Rafael Micro R820T/2 tuner
[INFO] Using format CF32.
Allocating 15 (non-zero-copy) user-space buffers
Stream closed
[INFO] Opening Generic RTL2832U OEM :: df47a2b4edae...
Found Rafael Micro R820T/2 tuner
[INFO] Using format CF32.
Allocating 15 (non-zero-copy) user-space buffers
Stream closed
[INFO] Opening Generic RTL2832U OEM :: df47a2b4edae...
Found Rafael Micro R820T/2 tuner
[INFO] Using format CF32.
Allocating 15 (non-zero-copy) user-space buffers
Stream closed
Windows fatal exception: access violation

Current thread 0x00000a0c (most recent call first):
  File "C:\Users\avioh\anaconda3\envs\rtlsdr-test-2\lib\site-packages\SoapySDR.py", line 1484 in unmake
  File "C:\Users\avioh\anaconda3\envs\rtlsdr-test-2\lib\site-packages\SoapySDR.py", line 1822 in close
  File "C:\Users\avioh\anaconda3\envs\rtlsdr-test-2\lib\site-packages\SoapySDR.py", line 1825 in __del__
  File "c:\xx\simple_test.py", line 25 in <module>

Additional Information:

Possible Cause:

Please let me know if you need further information, and I can provide more details.

zuckschwerdt commented 1 month ago

This smells like a double-free. For a quick fix note that closeStream will also deactivateStream and that dropping the reference to Device will also closeStream implicitly -- you should be okay to just del sdr. edit: actually __del__ will close and that in turn will unmake (as seen in the trace), streams are not implicitly closed. Strange then where unmake fails. SoapyRTLSDR's destructor has nothing but a rtlsdr_close(dev) call.

KeyserSoze-ND commented 1 month ago

I tried the following:

def main():  
    args = {'driver': 'rtlsdr'}  
    sdr = SoapySDR.Device(args)
    sdr.setSampleRate(SoapySDR.SOAPY_SDR_RX, 0, 2.048e6)
    sdr.setFrequency(SoapySDR.SOAPY_SDR_RX, 0, 100e6)    
    stream = sdr.setupStream(SoapySDR.SOAPY_SDR_RX, SoapySDR.SOAPY_SDR_CF32)
    sdr.activateStream(stream)
    time.sleep(1) 
    #sdr.deactivateStream(stream)
    sdr.closeStream(stream)
    print("Stream closed")
    time.sleep(1)

if __name__ == "__main__":    
    while True:
        main()

This fails the same way.

I also tried this:

def main():  
    args = {'driver': 'rtlsdr'}  
    sdr = SoapySDR.Device(args)
    sdr.setSampleRate(SoapySDR.SOAPY_SDR_RX, 0, 2.048e6)
    sdr.setFrequency(SoapySDR.SOAPY_SDR_RX, 0, 100e6)    
    stream = sdr.setupStream(SoapySDR.SOAPY_SDR_RX, SoapySDR.SOAPY_SDR_CF32)
    sdr.activateStream(stream)
    time.sleep(1) 
    del sdr
    print("Stream closed")
    time.sleep(1)

if __name__ == "__main__":    
    while True:
        main()

Interestingly, this does not crash but just hangs. The python kernel stops responding. (CTRL+C does not work etc.)

zuckschwerdt commented 1 month ago

I guess the first example might keep the sdr Device around and the second tries to force a close with an active stream, which won't work as the rtlsdr async is still running. All around your examples are valid and what should be expected to work from a Python perspective.

There are no clues why the unmake would fail after some tries. We likely need to try if this also appears in a similar C example and then debug the state, perhaps with gcc. I'll try to run this code on Linux and see if it can be reproduced. I hope it's not some Windows pecularity.

zuckschwerdt commented 1 month ago

I can't reproduce this in Linux, seems to be particular to Windows or your setup. Do you have WSL? Can you reproduce this in WSL? Are you up to trying the same example in C? That would make out or exclude Python as the culprit.

KeyserSoze-ND commented 1 month ago

I do not have WSL but VSCode has an extension for it so I will try to reproduce this in WSL. I never used this library in C but I can also try this with C while I am at it.

KeyserSoze-ND commented 1 month ago

Attached is the C code I ran in WSL (Debian). I do not run and capture samples repeatedly but just once.

#include <SoapySDR/Device.h>
#include <SoapySDR/Formats.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>

int main(void) {
    SoapySDRKwargs args = SoapySDRKwargs_fromString("driver=rtlsdr");
    SoapySDRDevice *sdr = SoapySDRDevice_make(&args);
    if (sdr == NULL) {
        fprintf(stderr, "Error: Failed to initialize RTL-SDR device.\n");
        return EXIT_FAILURE;
    }
    int result = SoapySDRDevice_setSampleRate(sdr, SOAPY_SDR_RX, 0, 1e6);
    if (result != 0) {
        fprintf(stderr, "Error: Failed to set sample rate.\n");
        SoapySDRDevice_unmake(sdr);
        return EXIT_FAILURE;
    }
    result = SoapySDRDevice_setFrequency(sdr, SOAPY_SDR_RX, 0, 100e6, NULL);
    if (result != 0) {
        fprintf(stderr, "Error: Failed to set frequency.\n");
        SoapySDRDevice_unmake(sdr);
        return EXIT_FAILURE;
    }
    SoapySDRKwargs streamArgs = SoapySDRKwargs_fromString("");
    SoapySDRKwargs_set(&streamArgs, "buffers", "4");
    SoapySDRKwargs_set(&streamArgs, "bufflen", "16384");
    size_t channels[1] = {0};
    size_t numChans = 1;
    const char *format = "CS16";

    int stream_initialized = 0;

    SoapySDRStream *rxStream = SoapySDRDevice_setupStream(sdr, SOAPY_SDR_RX, format, channels, numChans, &streamArgs);
    if (rxStream == NULL) {
        fprintf(stderr, "Error: Failed to set up stream.\n");
        SoapySDRDevice_unmake(sdr);
        SoapySDRKwargs_clear(&streamArgs);
        return EXIT_FAILURE;
    }
    SoapySDRKwargs_clear(&streamArgs);
    stream_initialized = 1;  
    result = SoapySDRDevice_activateStream(sdr, rxStream, 0, 0, 0);
    if (result != 0) {
        fprintf(stderr, "Error: Failed to activate stream.\n");
        SoapySDRDevice_unmake(sdr);
        return EXIT_FAILURE;
    }
    int numElems = 1024;
    int16_t *buff = (int16_t *)malloc(numElems * 2 * sizeof(int16_t));
    if (buff == NULL) {
        fprintf(stderr, "Error: Failed to allocate buffer.\n");
        SoapySDRDevice_unmake(sdr);
        return EXIT_FAILURE;
    }
    void *buffs[] = {buff};
    long long timeNs = 0;

    result = SoapySDRDevice_readStream(sdr, rxStream, buffs, numElems, NULL, &timeNs, 1000000);  // Timeout of 1 second
    if (result < 0) {
        fprintf(stderr, "Error: Failed to read stream. Error code: %d\n", result);
        free(buff);
        SoapySDRDevice_unmake(sdr);
        return EXIT_FAILURE;
    } else if (result == 0) {
        fprintf(stderr, "Warning: No samples read from the stream.\n");
    } else {
        printf("Captured %d samples successfully.\n", result);
    }

    if (stream_initialized) {
        SoapySDRDevice_deactivateStream(sdr, rxStream, 0, 0);
        SoapySDRDevice_closeStream(sdr, rxStream);
    }
    free(buff);
    SoapySDRDevice_unmake(sdr);
    printf("Stream closed.\n");
    return EXIT_SUCCESS;
}

When this code runs, I get the following error:

Found Rafael Micro R820T tuner
[INFO] Opening Generic RTL2832U OEM :: df47a2b4edae...
Found Rafael Micro R820T tuner
Exact sample rate is: 1000000.026491 Hz
[R82XX] PLL not locked!
[INFO] Using format CS16.
Allocating 15 zero-copy buffers
Segmentation fault (core dumped)

I also run using gdb to backtrace and then I receive the errors as:

Thread 1 "simple_sdr" received signal SIGSEGV, Segmentation fault.
0x00007ffff7a34238 in SoapyRTLSDR::acquireReadBuffer(SoapySDR::Stream*, unsigned long&, void const**, int&, long long&, long) () from /usr/local/lib/SoapySDR/modules0.8-3/librtlsdrSupport.so
(gdb) backtrace
#0  0x00007ffff7a34238 in SoapyRTLSDR::acquireReadBuffer(SoapySDR::Stream*, unsigned long&, void const**, int&, long long&, long) () from /usr/local/lib/SoapySDR/modules0.8-3/librtlsdrSupport.so
#1  0x00007ffff7a33d93 in SoapyRTLSDR::readStream(SoapySDR::Stream*, void* const*, unsigned long, int&, long long&, long) () from /usr/local/lib/SoapySDR/modules0.8-3/librtlsdrSupport.so
#2  0x00007ffff7f8b464 in SoapySDRDevice_readStream () from /usr/local/lib/libSoapySDR.so.0.8-3
#3  0x0000555555555588 in main () at simple_sdr.c:61

Despite these errors, rtl_testruns without any issues. I’ve tried it on another machine and observed the same problem.

Would you mind testing the previous Python code I posted in a Windows environment to see if the issue is reproducible? This might help narrow down if it's environment-specific. Thank you for your time and assistance!

zuckschwerdt commented 1 month ago

What you are seeing there is different. Fix it in line 61 with

int flags = 0;
result = SoapySDRDevice_readStream(sdr, rxStream, buffs, numElems, &flags, &timeNs, 1000000);  // Timeout of 1 second

Note that flags is an output and can't be NULL, https://github.com/pothosware/SoapySDR/blob/master/include/SoapySDR/Device.h#L392

KeyserSoze-ND commented 1 month ago

Thanks for that. I fixed the code as you suggested and it works now. Then I made it so that it is in a while loop and repeatedly runs and captures data. In this case, I observed no errors, so it runs without issue in C as opposed to Python.

Interestingly, while doing so, I realized the SoapySDRDevice_deactivateStreamor SoapySDRDevice_deactivateStreamis unnecessary for repeated runs. As an example, this code runs without any issues:

#include <SoapySDR/Device.h>
#include <SoapySDR/Formats.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>

int main(void) {
    SoapySDRKwargs args = SoapySDRKwargs_fromString("driver=rtlsdr");
    SoapySDRDevice *sdr = SoapySDRDevice_make(&args);
    if (sdr == NULL) {
        fprintf(stderr, "Error: Failed to initialize RTL-SDR device.\n");
        return EXIT_FAILURE;
    }

    int result = SoapySDRDevice_setSampleRate(sdr, SOAPY_SDR_RX, 0, 1e6);
    if (result != 0) {
        fprintf(stderr, "Error: Failed to set sample rate.\n");
        SoapySDRDevice_unmake(sdr);
        return EXIT_FAILURE;
    }

    result = SoapySDRDevice_setFrequency(sdr, SOAPY_SDR_RX, 0, 95e6, NULL);
    if (result != 0) {
        fprintf(stderr, "Error: Failed to set frequency.\n");
        SoapySDRDevice_unmake(sdr);
        return EXIT_FAILURE;
    }

    SoapySDRKwargs streamArgs = SoapySDRKwargs_fromString("");
    SoapySDRKwargs_set(&streamArgs, "buffers", "4");
    SoapySDRKwargs_set(&streamArgs, "bufflen", "65536");  // Increase buffer size
    size_t channels[1] = {0};
    size_t numChans = 1;
    const char *format = "CS16";
    SoapySDRStream *rxStream = SoapySDRDevice_setupStream(sdr, SOAPY_SDR_RX, format, channels, numChans, &streamArgs);

    if (rxStream == NULL) {
        fprintf(stderr, "Error: Failed to set up stream.\n");
        SoapySDRDevice_unmake(sdr);
        SoapySDRKwargs_clear(&streamArgs);
        return EXIT_FAILURE;
    }

    SoapySDRKwargs_clear(&streamArgs);

    result = SoapySDRDevice_activateStream(sdr, rxStream, 0, 0, 0);
    if (result != 0) {
        fprintf(stderr, "Error: Failed to activate stream.\n");
        SoapySDRDevice_unmake(sdr);
        return EXIT_FAILURE;
    }

    int numElems = 1024;
    int16_t *buff = (int16_t *)malloc(numElems * 4 * sizeof(int16_t)); 
    if (buff == NULL) {
        fprintf(stderr, "Error: Failed to allocate buffer.\n");
        SoapySDRDevice_unmake(sdr);
        return EXIT_FAILURE;
    }
    void *buffs[] = {buff};
    long long timeNs = 0;

    while (1) {
        int flags = 0;
        result = SoapySDRDevice_readStream(sdr, rxStream, buffs, numElems, &flags, &timeNs, 1000000);  // Timeout of 1 second
        if (result == SOAPY_SDR_TIMEOUT) {
            fprintf(stderr, "Timeout occurred while reading the stream. Retrying...\n");
            continue;  // Retry reading
        } else if (result == SOAPY_SDR_OVERFLOW) {
            fprintf(stderr, "Overflow occurred. Samples were dropped.\n");
            continue;  // Retry reading
        } else if (result < 0) {
            fprintf(stderr, "Error: Failed to read stream. Error code: %d\n", result);
            break;  // Exit the loop on fatal errors
        } else if (result == 0) {
            fprintf(stderr, "Warning: No samples read from the stream.\n");
        } else {
            printf("Captured %d samples successfully.\n", result);
        }
        usleep(100000);// This is necessary, otherwise stuck in timeout.
    }
}

Similarly, I then changed the python code I proposed in the first place:

import os
import ctypes
os.add_dll_directory(r'C:\PothosSDR\bin') 
ctypes.windll.LoadLibrary(r'C:\PothosSDR\\bin\rtlsdr.dll') 
import SoapySDR
import time
import numpy as np
import faulthandler
faulthandler.enable()

def initialize(args):
    sdr = SoapySDR.Device(args)
    sdr.setSampleRate(SoapySDR.SOAPY_SDR_RX, 0, 2.048e6)
    sdr.setFrequency(SoapySDR.SOAPY_SDR_RX, 0, 100e6)    
    stream = sdr.setupStream(SoapySDR.SOAPY_SDR_RX, SoapySDR.SOAPY_SDR_CF32)
    return sdr,stream

def read_data(sdr,stream):        
    sdr.activateStream(stream)
    buff = np.zeros((1024,),dtype=np.complex64)
    sr = sdr.readStream(stream, [buff], len(buff))
    print(sr.ret)
    time.sleep(1)  # Read data etc. and do processing
    print('I READ THE DATA')

# Unnecessary?    
def close_all(sdr,stream):
    sdr.deactivateStream(stream)
    sdr.closeStream(stream)
    #del sdr  # Ensure cleanup
    print("Stream closed")
    time.sleep(1)

if __name__ == "__main__":    
    args = {'driver': 'rtlsdr'}
    sdr,stream = initialize(args)
    while True:
        read_data(sdr,stream)

The code above runs without any issues which is great.

However, then the next question is that why the sdr.deactivate(stream) or sdr.closeStream(stream) exist in the first place if this can run without it even being called. What do they do?

KeyserSoze-ND commented 1 month ago

Just for completeness, I also tried to close the stream every time after I got some samples. Below is the code for that where I initialize the stream, read data and close everything again and again:

#include <SoapySDR/Device.h>
#include <SoapySDR/Formats.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>

int main(void) {
    while (1) {
        SoapySDRKwargs args = SoapySDRKwargs_fromString("driver=rtlsdr");
        SoapySDRDevice *sdr = SoapySDRDevice_make(&args);
        if (sdr == NULL) {
            fprintf(stderr, "Error: Failed to initialize RTL-SDR device.\n");
            return EXIT_FAILURE;
        }

        int result = SoapySDRDevice_setSampleRate(sdr, SOAPY_SDR_RX, 0, 1e6);
        if (result != 0) {
            fprintf(stderr, "Error: Failed to set sample rate.\n");
            SoapySDRDevice_unmake(sdr);
            return EXIT_FAILURE;
        }

        result = SoapySDRDevice_setFrequency(sdr, SOAPY_SDR_RX, 0, 95e6, NULL);
        if (result != 0) {
            fprintf(stderr, "Error: Failed to set frequency.\n");
            SoapySDRDevice_unmake(sdr);
            return EXIT_FAILURE;
        }

        SoapySDRKwargs streamArgs = SoapySDRKwargs_fromString("");
        SoapySDRKwargs_set(&streamArgs, "buffers", "4");
        SoapySDRKwargs_set(&streamArgs, "bufflen", "65536");
        size_t channels[1] = {0};
        size_t numChans = 1;
        const char *format = "CS16";
        SoapySDRStream *rxStream = SoapySDRDevice_setupStream(sdr, SOAPY_SDR_RX, format, channels, numChans, &streamArgs);

        if (rxStream == NULL) {
            fprintf(stderr, "Error: Failed to set up stream.\n");
            SoapySDRDevice_unmake(sdr);
            SoapySDRKwargs_clear(&streamArgs);
            return EXIT_FAILURE;
        }

        SoapySDRKwargs_clear(&streamArgs);

        result = SoapySDRDevice_activateStream(sdr, rxStream, 0, 0, 0);
        if (result != 0) {
            fprintf(stderr, "Error: Failed to activate stream.\n");
            SoapySDRDevice_unmake(sdr);
            return EXIT_FAILURE;
        }

        int numElems = 4096;
        int16_t *buff = (int16_t *)malloc(numElems * 4 * sizeof(int16_t)); 
        if (buff == NULL) {
            fprintf(stderr, "Error: Failed to allocate buffer.\n");
            SoapySDRDevice_unmake(sdr);
            return EXIT_FAILURE;
        }
        void *buffs[] = {buff};
        long long timeNs = 0;

        // Enter a loop to continuously capture samples

        int flags = 0;
        result = SoapySDRDevice_readStream(sdr, rxStream, buffs, numElems, &flags, &timeNs, 1000000);  // Timeout of 1 second
        if (result == SOAPY_SDR_TIMEOUT) {
            fprintf(stderr, "Timeout occurred while reading the stream. Retrying...\n");
            continue;  // Retry reading
        } else if (result == SOAPY_SDR_OVERFLOW) {
            fprintf(stderr, "Overflow occurred. Samples were dropped.\n");
            continue;  // Retry reading
        } else if (result < 0) {
            fprintf(stderr, "Error: Failed to read stream. Error code: %d\n", result);
            break;  // Exit the loop on fatal errors
        } else if (result == 0) {
            fprintf(stderr, "Warning: No samples read from the stream.\n");
        } else {
            printf("Captured %d samples successfully.\n", result);
        }        
        SoapySDRDevice_deactivateStream(sdr, rxStream, 0, 0);
        fprintf(stderr, "1\n");
        SoapySDRDevice_closeStream(sdr, rxStream);
        fprintf(stderr, "2\n");
        free(buff);
        fprintf(stderr, "3\n");
        SoapySDRDevice_unmake(sdr);
        fprintf(stderr, "4\n");
        printf("Stream closed.\n");
        usleep(100000);  // Add a small delay between captures (100ms)
    }    
    return EXIT_SUCCESS;
}

There are no issues for this code in WSL (Debian) in Win11. But the initial Python code I proposed fails for some reason (in Win11).

zuckschwerdt commented 1 month ago

There are no guarantees that closeStream() will implicitly call deactivateStream() I think. It's always safer to issue all needed calls.

The open /activate /deactivate /close sequence is needed to set up /clean up (hardware) resources. Depending on the SDR device they will perform different things and might not strictly be needed.

I'd only close /reopen a device if I want to free the hardware, e.g. when the program keeps running but is done with the SDR. I'd use de/activate every time I pause the stream, i.e. when I don't want samples to be contiguous.

zuckschwerdt commented 1 month ago

Ok, we now have narrowed the bug down to Python on Windows doing something unexpected with memory locations. That's complicated to debug I guess. I'd trace the call graph or maybe easier pepper the SoapyRTLSDR source with debug prints and then follow the sequence of calls in the terminal. Some call must be duplicate or with wrong arguments.