Question

I am trying to send wav files in C++ via TCP on Linux over a socket but I don't understand how a wav file can be read correctly.

My goal is to read the file on the client into a char array, send it with "write()" to the server, and the server should write the data into a local wav file again.

I read the .wav file like this:

////////////define socket - left out for simplicity

ifstream file ("audio.wav", ios::in|ios::binary|ios::ate); //open .wav file
char * buffer; //declare data buffer, should contain .wav data to write to socket
streampos filesize; //size of file
int n; //number of written bytes

//if file opened correctly, read content and write to socket
if (file.is_open()){
    filesize = file.tellg();
    buffer = new char [filesize];
    file.seekg (0, ios::beg);
    file.read (buffer, filesize);
    file.close();
    n = write(socket, buffer, sizeof(buffer));
 }

On the server, this returns the array "RIFF" of length "4", so its part of the header of the wav file.

How can I read the whole .wav file content correctly for writing to the TCP socket?

Thanks.

Was it helpful?

Solution

That is simple: filesize is size of the file in bytes. However, sizeof(buffer) is only 4 on a 32-bit OS. Modify your code like this:

if(file.is_open()) {
    filesize = file.tellg();
    buffer = new char [filesize];
    file.seekg (0, ios::beg);
    file.read (buffer, filesize);
    file.close();
    n = write_all(socket, buffer, filesize); // use filesize here
    delete[] buffer; // !!
}

To simplify processing on the other side, you may want to send filesize first to avoid parsing of the RIFF header to know how many bytes to accept. I would also suggest allocating a smaller buffer and reading several times to send the larger files over:

if(file.is_open()) {
    filesize = file.tellg();
    file.seekg(0, ios::beg);

    uint32_t remains = filesize;
    write(socket, &remains, sizeof(uint32_t));
    // write 4B with size of the file (optional)

    buffer = new char[(filesize > 4096)? 4096 : filesize];
    // only up to 4k buffer to avoid running out of memory

    n = 0;
    while(remains > 0) {
        int chunk = (remains > 4096)? 4096 : remains;
        // decide how much to read in at one time (not more than size of the buffer)

        file.read(buffer, chunk);
        n += write_all(socket, buffer, chunk);
        // read a chunk and write it to the socket

        remains -= chunk;
        // update number of bytes that remains to be transferred
    }
    // send the file several times

    file.close();
    delete[] buffer; // !!
}

You may notice the use of a helper function write_all. That is required, because the socket might get full and then write will not write all the data given to it. It could look like this:

size_t write_all(int socket, const char *buffer, size_t size)
{
    size_t n = 0;
    while(size > 0) {
        size_t written = write(socket, buffer, size);
        if(written == -1)
            return written; // handle errors
        n += written;
        size -= written;
    }
    return n;
}

OTHER TIPS

buffer is of type char*, so sizeof(buffer) is the size of an ordinary data pointer on your platform. So you're writing 4 or 8 bytes (assuming ordinary plateform) to your socket.

You need to put filesize in the write call instead of sizeof(buffer).

(sizeof is a compile-time construct. It's evaluated when your code is compiled. It can't return a size that's determined at runtime.)

In the line n = write(socket, buffer, sizeof(buffer)); the value of the last buffer becomes the size of a pointer on your platform. Since only four bytes are sent, I will assume that you are either on a 32-bit platform or compiling the application in 32-bit mode.

Replacing sizeof(buffer) will only be a partial solution since write() may not write all the data at once. You will need to check the value returned from write() and keep record of how many bytes have been written to the socket.

I used sndfile for handling wav files.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top