ERROR when sampling audio from ESP32 - Timeout or Undeterminated nesting

Hi,

First of all. You guys made a great platform here. Love it.
Now to the problem. I have an ESP32 dev board with a I2S microphone connected to my PC and trying to get sample data with edge-impulse-deamon. It seems like when the file is bigger i get a time out. But when i reduce the Sample Length it says
“‘Invalid message body, was specified to be CBOR but could not decode message (Undeterminated nesting)’”

Settings:
Frequency: 8000
Sample Length: 10000

I get this error:

[SER] Sampling started
[SER] Sampling done
[SER] Device not connected to WiFi directly, reading from buffer (bytes 0 - 164084, expecting to read ~218778 bytes...
[SER] Reading 28% complete...
[SER] Reading 71% complete...
[WS ] Failed to sample data Timeout when waiting for
OK (timeout: 130000) AT+READBUFFER=0,164084,y

When i do the same with these setting i get another error.
Frequency: 8000
Sample Length: 2000

[WS ] Incoming sampling request {
  path: '/api/training/data',
  label: 'ESP32',
  length: 2000,
  interval: 0.125,
  hmacKey: '31d47728ffafa1886b1705846124320b',
  sensor: 'Built-in microphone'
}
[SER] Configured upload settings
[SER] Sampling started
[SER] Sampling done
[SER] Device not connected to WiFi directly, reading from buffer (bytes 0 - 33012, expecting to read ~44016 bytes...
[SER] Reading from buffer OK
[SER] File is 243 bytes after decoding
[SER] Uploading to https://ingestion.edgeimpulse.com/api/training/data
[SER] Failed to upload to https://ingestion.edgeimpulse.com/api/training/data StatusCodeError: 400 - "Invalid message body, was specified to be CBOR but could not decode message (Undeterminated nesting)"
    at new StatusCodeError (E:\edsteve\AppData\Roaming\npm\node_modules\edge-impulse-cli\node_modules\request-promise-core\lib\errors.js:32:15)
    at plumbing.callback (E:\edsteve\AppData\Roaming\npm\node_modules\edge-impulse-cli\node_modules\request-promise-core\lib\plumbing.js:104:33)
    at Request.RP$callback [as _callback] (E:\edsteve\AppData\Roaming\npm\node_modules\edge-impulse-cli\node_modules\request-promise-core\lib\plumbing.js:46:31)
    at self.callback (E:\edsteve\AppData\Roaming\npm\node_modules\edge-impulse-cli\node_modules\request\request.js:185:22)
    at Request.emit (node:events:512:28)
    at Request.<anonymous> (E:\edsteve\AppData\Roaming\npm\node_modules\edge-impulse-cli\node_modules\request\request.js:1161:10)
    at Request.emit (node:events:512:28)
    at IncomingMessage.<anonymous> (E:\edsteve\AppData\Roaming\npm\node_modules\edge-impulse-cli\node_modules\request\request.js:1083:12)
    at Object.onceWrapper (node:events:626:28)
    at IncomingMessage.emit (node:events:524:35)
    at endReadableNT (node:internal/streams/readable:1359:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  statusCode: 400,
  error: 'Invalid message body, was specified to be CBOR but could not decode message (Undeterminated nesting)',
  options: {
    headers: {
      'x-api-key': 'ei_c00135be8be56d0ed7a76e57377bf4a26934d0b531ad8894f29c1e409563d040',
      'x-file-name': 'ESP32',
      'Content-Type': 'application/cbor'
    },
    body: <Buffer a3 69 70 72 6f 74 65 63 74 65 64 a2 63 76 65 72 62 76 31 63 61 6c 67 65 48 53 32 35 36 69 73 69 67 6e 61 74 75 72 65 78 40 35 31 37 63 36 32 33 39 30 ... 193 more bytes>,
    encoding: 'binary',
    uri: 'https://ingestion.edgeimpulse.com/api/training/data',
    method: 'POST',
    callback: [Function: RP$callback],
    transform: undefined,
    simple: true,
    resolveWithFullResponse: false,
    transform2xxOnly: false
  },
  response: <ref *1> IncomingMessage {
    _readableState: ReadableState {
      objectMode: false,
      highWaterMark: 16384,
      buffer: BufferList { head: null, tail: null, length: 0 },
      length: 0,
      pipes: [],
      flowing: true,
      ended: true,
      endEmitted: true,
      reading: false,
      constructed: true,
      sync: false,
      needReadable: false,
      emittedReadable: false,
      readableListening: false,
      resumeScheduled: false,
      errorEmitted: false,
      emitClose: true,
      autoDestroy: true,
      destroyed: true,
      errored: null,
      closed: true,
      closeEmitted: true,
      defaultEncoding: 'utf8',
      awaitDrainWriters: null,
      multiAwaitDrain: false,
      readingMore: false,
      dataEmitted: true,
      decoder: [StringDecoder],
      encoding: 'latin1',
      [Symbol(kPaused)]: false
    },
    _events: [Object: null prototype] {
      end: [Array],
      close: [Array],
      data: [Function (anonymous)],
      error: [Function (anonymous)]
    },
    _eventsCount: 4,
    _maxListeners: undefined,
    socket: null,
    httpVersionMajor: 1,
    httpVersionMinor: 1,
    httpVersion: '1.1',
    complete: true,
    rawHeaders: [
      'Date',
      'Tue, 14 Feb 2023 17:30:05 GMT',
      'Content-Type',
      'text/plain',
      'Transfer-Encoding',
      'chunked',
      'Connection',
      'keep-alive',
      'Access-Control-Allow-Origin',
      '*',
      'Content-Security-Policy',
      "default-src 'none'; frame-ancestors 'none'; form-action 'none';",
      'X-Content-Type-Options',
      'nosniff',
      'X-Frame-Options',
      'DENY',
      'X-XSS-Protection',
      '1; mode=block',
      'Referrer-Policy',
      'strict-origin',
      'Cache-Control',
      's-maxage=0,public,no-cache,no-store,must-revalidate',
      'Strict-Transport-Security',
      'max-age=63072000'
    ],
    rawTrailers: [],
    joinDuplicateHeaders: undefined,
    aborted: false,
    upgrade: false,
    url: '',
    method: null,
    statusCode: 400,
    statusMessage: 'Bad Request',
    client: TLSSocket {
      _tlsOptions: [Object],
      _secureEstablished: true,
      _securePending: false,
      _newSessionPending: false,
      _controlReleased: true,
      secureConnecting: false,
      _SNICallback: null,
      servername: 'ingestion.edgeimpulse.com',
      alpnProtocol: false,
      authorized: true,
      authorizationError: null,
      encrypted: true,
      _events: [Object: null prototype],
      _eventsCount: 9,
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: 'ingestion.edgeimpulse.com',
      _closeAfterHandlingError: false,
      _readableState: [ReadableState],
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: false,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: undefined,
      _server: null,
      ssl: [TLSWrap],
      _requestCert: true,
      _rejectUnauthorized: true,
      timeout: 5000,
      parser: null,
      _httpMessage: null,
      [Symbol(res)]: [TLSWrap],
      [Symbol(verified)]: true,
      [Symbol(pendingSession)]: null,
      [Symbol(async_id_symbol)]: -1,
      [Symbol(kHandle)]: [TLSWrap],
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: Timeout {
        _idleTimeout: 5000,
        _idlePrev: [TimersList],
        _idleNext: [TimersList],
        _idleStart: 25488,
        _onTimeout: [Function: bound ],
        _timerArgs: undefined,
        _repeat: null,
        _destroyed: false,
        [Symbol(refed)]: false,
        [Symbol(kHasPrimitive)]: false,
        [Symbol(asyncId)]: 3160,
        [Symbol(triggerId)]: 3157
      },
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kSetNoDelay)]: false,
      [Symbol(kSetKeepAlive)]: true,
      [Symbol(kSetKeepAliveInitialDelay)]: 1,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(connect-options)]: [Object]
    },
    _consuming: true,
    _dumped: false,
    req: ClientRequest {
      _events: [Object: null prototype],
      _eventsCount: 5,
      _maxListeners: undefined,
      outputData: [],
      outputSize: 0,
      writable: true,
      destroyed: true,
      _last: false,
      chunkedEncoding: false,
      shouldKeepAlive: true,
      maxRequestsOnConnectionReached: false,
      _defaultKeepAlive: true,
      useChunkedEncodingByDefault: true,
      sendDate: false,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      strictContentLength: false,
      _contentLength: 243,
      _hasBody: true,
      _trailer: '',
      finished: true,
      _headerSent: true,
      _closed: true,
      socket: [TLSSocket],
      _header: 'POST /api/training/data HTTP/1.1\r\n' +
        'x-api-key: ei_c00135be8be56d0ed7a76e57377bf4a26934d0b531ad8894f29c1e409563d040\r\n' +
        'x-file-name: ESP32\r\n' +
        'Content-Type: application/cbor\r\n' +
        'host: ingestion.edgeimpulse.com\r\n' +
        'content-length: 243\r\n' +
        'Connection: keep-alive\r\n' +
        '\r\n',
      _keepAliveTimeout: 0,
      _onPendingData: [Function: nop],
      agent: [Agent],
      socketPath: undefined,
      method: 'POST',
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      joinDuplicateHeaders: undefined,
      path: '/api/training/data',
      _ended: true,
      res: [Circular *1],
      aborted: false,
      timeoutCb: null,
      upgradeOrConnect: false,
      parser: null,
      maxHeadersCount: null,
      reusedSocket: false,
      host: 'ingestion.edgeimpulse.com',
      protocol: 'https:',
      [Symbol(kCapture)]: false,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(kEndCalled)]: true,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype],
      [Symbol(errored)]: null,
      [Symbol(kUniqueHeaders)]: null
    },
    request: Request {
      _events: [Object: null prototype],
      _eventsCount: 5,
      _maxListeners: undefined,
      headers: [Object],
      body: <Buffer a3 69 70 72 6f 74 65 63 74 65 64 a2 63 76 65 72 62 76 31 63 61 6c 67 65 48 53 32 35 36 69 73 69 67 6e 61 74 75 72 65 78 40 35 31 37 63 36 32 33 39 30 ... 193 more bytes>,
      encoding: 'binary',
      uri: [Url],
      method: 'POST',
      readable: true,
      writable: true,
      explicitMethod: true,
      _qs: [Querystring],
      _auth: [Auth],
      _oauth: [OAuth],
      _multipart: [Multipart],
      _redirect: [Redirect],
      _tunnel: [Tunnel],
      _rp_resolve: [Function (anonymous)],
      _rp_reject: [Function (anonymous)],
      _rp_promise: [Promise [Object]],
      _rp_callbackOrig: undefined,
      callback: [Function (anonymous)],
      _rp_options: [Object],
      setHeader: [Function (anonymous)],
      hasHeader: [Function (anonymous)],
      getHeader: [Function (anonymous)],
      removeHeader: [Function (anonymous)],
      localAddress: undefined,
      pool: {},
      dests: [],
      __isRequestRequest: true,
      _callback: [Function: RP$callback],
      proxy: null,
      tunnel: true,
      setHost: true,
      originalCookieHeader: undefined,
      _disableCookies: true,
      _jar: undefined,
      port: 443,
      host: 'ingestion.edgeimpulse.com',
      path: '/api/training/data',
      httpModule: [Object],
      agentClass: [Function: Agent],
      agent: [Agent],
      _started: true,
      href: 'https://ingestion.edgeimpulse.com/api/training/data',
      req: [ClientRequest],
      ntick: true,
      response: [Circular *1],
      originalHost: 'ingestion.edgeimpulse.com',
      originalHostHeaderName: 'host',
      responseContent: [Circular *1],
      _destdata: true,
      _ended: true,
      _callbackCalled: true,
      [Symbol(kCapture)]: false
    },
    toJSON: [Function: responseToJSON],
    caseless: Caseless { dict: [Object] },
    body: 'Invalid message body, was specified to be CBOR but could not decode message (Undeterminated nesting)',
    [Symbol(kCapture)]: false,
    [Symbol(kHeaders)]: {
      date: 'Tue, 14 Feb 2023 17:30:05 GMT',
      'content-type': 'text/plain',
      'transfer-encoding': 'chunked',
      connection: 'keep-alive',
      'access-control-allow-origin': '*',
      'content-security-policy': "default-src 'none'; frame-ancestors 'none'; form-action 'none';",
      'x-content-type-options': 'nosniff',
      'x-frame-options': 'DENY',
      'x-xss-protection': '1; mode=block',
      'referrer-policy': 'strict-origin',
      'cache-control': 's-maxage=0,public,no-cache,no-store,must-revalidate',
      'strict-transport-security': 'max-age=63072000'
    },
    [Symbol(kHeadersCount)]: 24,
    [Symbol(kTrailers)]: null,
    [Symbol(kTrailersCount)]: 0
  }
}

Or this message:

[SER] Reading 71% complete...
[SER] Reading from buffer OK
[SER] File is 275 bytes after decoding
[SER] Uploading to https://ingestion.edgeimpulse.com/api/training/data
[SER] Failed to upload to https://ingestion.edgeimpulse.com/api/training/data StatusCodeError: 400 - "Invalid message body, was specified to be CBOR but could not decode message (Failed to parse)"

Hi @edsteve,

Please see this discussion on sending CBOR data to a Studio project using the edge-impulse-daemon: Json to Cbor then to Base64 to upload data with Serial Daemon.

Note that audio data might be too long to be serialized (I have not tested it myself).

If you are using an ESP32, another option might be to send data directly to your Studio project using the ingestion API (rather than having to go through your computer with the daemon): Data acquisition format - Edge Impulse API

Hope that helps!

1 Like

Thanks for your reply. So these links are the only two ways to get audio data from my ESP32 to Edge Impulse?
Unfortunately these solutions look fairly difficult for a script kiddy like me. Haha. I don’t think i am able to do that :frowning:

I tried with 500ms of audio. That is still too long?
Is that problem only on my side or uploading audio via serial does not work in general?

The ESP32 is fully supported by the Edge Impulse Daemon tool, so you can send Microphone data to Edge Impulse directly, just see the ESP32-CAM firmware and modify it as you want, I’ve done this to run the firmware on ESP32 normal cores. See here: GitHub - mcmchris/wisblock-edge-impulse: This repository contains the Edge Impulse firmwares for the WisBlock ecosystem

1 Like

Thanks for your reply. I followed your tutorial from Github and found out that the browser was the problem. In Chrome it works like a charm without starting the deamon manually from command line. Awesome I am very happy now :slight_smile:

Question: My sampled sound from the device is pretty bad (I am using the INMP411 I2S mic right now). Very quiet and noisy. When i use the same setup and record to an SD card the sound is clear and loud.
I can see in your wave form that you don’t have that problem. You are using a PDM microphone. I have a PDM as well here i could try. Did you modify the code for reading the microphone or did it work out of the box?

@edsteve If you are looking for a response from mcmchris put an @ sign infront of his username, @mcmchris, and he will get notified.

Hi @edsteve I am using a PDM microphone from RAK and I just needed to define the pins of the connection and nothing else, and it works.

1 Like

hello mate, i am having the same problem, i tried using
mcmchris solution, and now it allows me to upload, but it doesn’t record, so i am uploading an empty file, did you solve this problem? @edsteve