Creating buffer

So I’m having trouble creating a buffer from an audio file (it will be a .ogg file) located on an SD card. I’m trying to acquire this buffer so that I can send it over MQTT to a server so that it can be dealt with on the server. Currently, I have been successful in reading and writing to a text file on an SD card. My question is, is there a library or example code that will help me read in a audio file and save it as a buffer? Is there something that I can do to understand this process better. Is there a better way to go about sending an audio file over MQTT? Any help will be appreciated, thank you!

When you read the data from a text file off the SD card you probably already have stored the read data in a buffer.
If you save text or binary data in a RAM based buffer isn't any different when it comes to the actual code.

1 Like

So the update is that I have been able to store the read data as a buffer but the problem is there seems to be a maximum size that I can send before the particle E-Series starts flashing a red light (SOS than 13 meaning stack overflow). I have also yet to be sucessful to get the entire file into a buffer. Another issue that I have is that when I try to send the buffer in groups of 4096, I seem to be just sending the first 4096 bytes over and over again and it also to crashs. I’m not really sure how to get the entire buffer of about 56 kb over to the server, this is the code that am using:

#include <MQTT.h>
#include <SparkJson.h>
#include <SdFat.h>
#include <SdFat.h>
#include <SparkJson.h>
#include <MQTT.h>
#include <stdio.h>
SdFat SD;
File recording;
#define CARDCS A2
#define ORG "XXXX"
#define DEVICE_TYPE "XXXX"
#define DEVICE_ID "XXXX"
#define TOKEN "XXXX"
char server[] = ORG "XXXX";
char authMethod[] = "use-token-auth";
char token[] = TOKEN;
char clientId[] = "d:" ORG ":" DEVICE_TYPE ":" DEVICE_ID;
const char publishTopic[] = "iot-2/evt/status/fmt/json";
const char responseTopic[] = "iotdm-1/response";
const char manageTopic[] = "iotdevice-1/mgmt/manage";
const char updateTopic[] = "iotdm-1/device/update";
const char rebootTopic[] = "iotdm-1/mgmt/initiate/device/reboot";
int publishInterval = 5000; 
long lastPublishMillis;
MQTT client(server, 1883, MQTT_DEFAULT_KEEPALIVE, callback, 8192); // max 512 bytes
void callback(char *topic, byte *payload, unsigned int payloadLength)
{
    Serial.print("callback invoked for topic: ");
    Serial.println(topic);
    if (strcmp(responseTopic, topic) == 0)
    {
        return; // just print of response for now
    }
    if (strcmp(rebootTopic, topic) == 0)
    {
        Serial.println("Rebooting...");
    }
    if (strcmp(updateTopic, topic) == 0)
    {
        handleUpdate(payload);
    }
}
void handleUpdate(byte *payload)
{
    StaticJsonBuffer<300> jsonBuffer;
    JsonObject &root = jsonBuffer.parseObject((char *)payload);
    if (!root.success())
    {
        Serial.println("handleUpdate: payload parse FAILED");
        return;
    }
    Serial.println("handleUpdate payload:");
    root.prettyPrintTo(Serial);
    Serial.println();
    JsonObject &d = root["d"];
    JsonArray &fields = d["fields"];
    for (JsonArray::iterator it = fields.begin(); it != fields.end(); ++it)
    {
        JsonObject &field = *it;
        const char *fieldName = field["field"];
        if (strcmp(fieldName, "metadata") == 0)
        {
            JsonObject &fieldValue = field["value"];
            if (fieldValue.containsKey("publishInterval"))
            {
                publishInterval = fieldValue["publishInterval"];
                Serial.print("publishInterval:");
                Serial.println(publishInterval);
            }
        }
    }
}
void setup()
{
    Serial.begin(115200);
    Serial.println();
    if (!SD.begin(CARDCS))
    {
        Serial.println("SD failed, or not present");
        while (1)
            ; // don't do anything more
    }
    Serial.println("SD OK!");
    mqttConnect();
    initManagedDevice();
    recording = SD.open("audio.WAV", FILE_READ);
}
void mqttConnect()
{
    if (!client.isConnected())
    {
        Serial.print("Reconnecting MQTT client to ");
        Serial.println(server);
        while (!client.connect(clientId, authMethod, token))
        {
            Serial.print(".");
            delay(10000);
        }
        Serial.println();
    }
}
void initManagedDevice()
{
    if (client.subscribe("iotdm-1/response"))
    {
        Serial.println("subscribe to responses OK");
    }
    else
    {
        Serial.println("subscribe to responses FAILED");
    }
    if (client.subscribe(rebootTopic))
    {
        Serial.println("subscribe to reboot OK");
    }
    else
    {
        Serial.println("subscribe to reboot FAILED");
    }
    if (client.subscribe("iotdm-1/device/update"))
    {
        Serial.println("subscribe to update OK");
    }
    else
    {
        Serial.println("subscribe to update FAILED");
    }
    StaticJsonBuffer<300> jsonBuffer;
    JsonObject &root = jsonBuffer.createObject();
    JsonObject &d = root.createNestedObject("d");
    JsonObject &metadata = d.createNestedObject("metadata");
    metadata["publishInterval"] = publishInterval;
    JsonObject &supports = d.createNestedObject("supports");
    supports["deviceActions"] = true;
    char buff[300];
    root.printTo(buff, sizeof(buff));
    Serial.println("publishing device metadata:");
    Serial.println(buff);
    if (client.publish(manageTopic, buff))
    {
        Serial.println("device Publish ok");
    }
    else
    {
        Serial.print("device Publish failed:");
    }
}
void loop()
{
    publishData();
    if (!client.loop())
    {
        mqttConnect();
    }
}
void publishData()
{
    int size = 4096;
    char buff[size];
    for (int i = 0; i < size; i++)
    {
        buff[i] = recording.read();
    }
    // if(buff[i] == -1){
    //     client.publish(publishTopic, (byte*)buff, size);
    //     Serial.println("Publish OK");
    //     break;
    // }
    // if(i == 4096){
    //     client.publish(publishTopic, (byte*)buff, size);
    //     Serial.println("Publish OK");
    // }
    Serial.print("Sending payload: ");
    Serial.println("DONE");
    if (client.publish(publishTopic, (byte *)buff, 4096))
    {
        Serial.println("Publish OK");
    }
    else
    {
        Serial.println("Publish FAILED");
    }
}

Depending on the file size that might be impossible due to limited RAM and stack size but most likely also unnecessary.
You can only send 512 byte chunks at once with the Electron, so no need to hold much more than that in RAM at any given time.

Before looking at your code, that's probably because you are writing the new data outside of your buffer instead of starting back at the beginning again.

BTW, why are you including the same headers multiple times?

After skimming over your code, you don't seem to check whether you reached the end of the file, but still keep on reading forever.
And I'm positive, there are other functions in SdFat that would be better suited to read into a buffer directly.
e.g.

  /** Read data from a file starting at the current position.
   *
   * \param[out] buf Pointer to the location that will receive the data.
   *
   * \param[in] nbyte Maximum number of bytes to read.
   *
   * \return For success read() returns the number of bytes read.
   * A value less than \a nbyte, including zero, will be returned
   * if end of file is reached.
   * If an error occurs, read() returns -1.  Possible errors include
   * read() called before a file has been opened, corrupt file system
   * or an I/O error occurred.
   */
  int read(void* buf, size_t nbyte);