Called in an infinite loop, read SaopySDR device to build a 'this.numElems' sized batch of samples (SDRThreadIQData) and push it into iqDataOutQueue. this batch of samples is built to represent 1 frame / TARGET_DISPLAY_FPS.
| 193 | // a 'this.numElems' sized batch of samples (SDRThreadIQData) and push it into iqDataOutQueue. |
| 194 | //this batch of samples is built to represent 1 frame / TARGET_DISPLAY_FPS. |
| 195 | int SDRThread::readStream(const SDRThreadIQDataQueuePtr& iqDataOutQueue) { |
| 196 | |
| 197 | int flags(0); |
| 198 | |
| 199 | long long timeNs(0); |
| 200 | |
| 201 | // Supply a huge timeout value to neutralize the readStream 'timeout' effect |
| 202 | // we are not interested in, but some modules may effectively use. |
| 203 | //TODO: use something roughly (1 / TARGET_DISPLAY_FPS) seconds * (factor) instead.? |
| 204 | long timeoutUs = (1 << 30); |
| 205 | |
| 206 | int n_read = 0; |
| 207 | int nElems = numElems.load(); |
| 208 | int mtElems = mtuElems.load(); |
| 209 | |
| 210 | // Warning: if MTU > numElems, i.e if device MTU is too big w.r.t the sample rate, the TARGET_DISPLAY_FPS cannot |
| 211 | //be reached and the CubicSDR displays "slows down". |
| 212 | //To get back a TARGET_DISPLAY_FPS, the user need to adapt |
| 213 | //the SoapySDR Device to use smaller buffer sizes, because |
| 214 | // readStream() is suited to device MTU and cannot be really adapted dynamically. |
| 215 | //TODO: Add in doc the need to reduce SoapySDR device buffer length (if available) to restore higher fps. |
| 216 | |
| 217 | //0. Retrieve a new batch |
| 218 | SDRThreadIQDataPtr dataOut = buffers.getBuffer(); |
| 219 | |
| 220 | //resize to the target size immedialetly, to minimize later reallocs: |
| 221 | assureBufferMinSize(dataOut.get(), nElems); |
| 222 | |
| 223 | //1.If overflow occurred on the previous readStream(), transfer it in dataOut directly. |
| 224 | if (numOverflow > 0) { |
| 225 | int n_overflow = std::min(numOverflow, nElems); |
| 226 | |
| 227 | //safety |
| 228 | assureBufferMinSize(dataOut.get(), n_overflow); |
| 229 | |
| 230 | ::memcpy(&dataOut->data[0], &overflowBuffer.data[0], n_overflow * sizeof(liquid_float_complex)); |
| 231 | n_read = n_overflow; |
| 232 | |
| 233 | //is still > 0 if MTU > nElements (low sample rate w.r.t the MTU !) |
| 234 | numOverflow -= n_overflow; |
| 235 | |
| 236 | // std::cout << "SDRThread::readStream() 1.1 overflowBuffer not empty, collect the remaining " << n_overflow << " samples in it..." << std::endl; |
| 237 | |
| 238 | if (numOverflow > 0) { // still some left, shift the remaining samples to the beginning. |
| 239 | ::memmove(&overflowBuffer.data[0], &overflowBuffer.data[n_overflow], numOverflow * sizeof(liquid_float_complex)); |
| 240 | |
| 241 | // std::cout << "SDRThread::readStream() 1.2 overflowBuffer still not empty, compact the remaining " << numOverflow << " samples in it..." << std::endl; |
| 242 | } |
| 243 | } //end if numOverflow > 0 |
| 244 | |
| 245 | //default means blocking. |
| 246 | int readStreamCode = 0; |
| 247 | |
| 248 | //2. attempt readStream() at most nElems, by mtElems-sized chunks, append in dataOut->data directly. |
| 249 | while (n_read < nElems && !stopping) { |
| 250 | |
| 251 | //Whatever the number of remaining samples needed to reach nElems, we always try to read a mtElems-size chunk, |
| 252 | //from which SoapySDR effectively returns n_stream_read. |