1

I have a C server that uses libwebsockets and I want to save a received audio stream in a file on disk.

Here is my code snippet:

#define FILENAME        "/home/ubuntu/Desktop/file.wav"
FILE *received_file;

struct lws_context *Audiocontext;
static int callback_audio(
        struct lws *wsi,
        enum lws_callback_reasons reason,
        void *user, void *in, size_t len)
{
    switch (reason) {
        case LWS_CALLBACK_ESTABLISHED: 
        {
            printf("client is connected\n");
            received_file = fopen(FILENAME, "w+");
            if (received_file == NULL)
            {
                printf("Failed to open file\n");
                exit(EXIT_FAILURE);
            }
        }
        break;
        case LWS_CALLBACK_RECEIVE: {
            if(strcmp((char*)in,"EOS")==0)
            {
                printf("End of stream!\n");
                fclose(received_file);
            }
            else
            {
                fwrite(in, 1, len, received_file);
            }
        }
    }
}

I got the message "client is connected" and also the file, but the content isn't ok, I cannot play it. I think there is a problem regarding the way I save the stream on file using fwrite().

The client is sending audio chunks encoded as wav, 16Khz, mono. Here is a snippet from client (it's a javascript client, the full code is here:http://kaljurand.github.io/dictate.js/).

if (recorder) {
    recorder.stop();
    config.onEvent(MSG_STOP, 'Stopped recording');
    // Push the remaining audio to the server
    recorder.export16kMono(function(blob) {
        socketSend(blob);
        socketSend(TAG_END_OF_SENTENCE);
        recorder.clear();
        }, 'export16kMono');
    config.onEndOfSpeech();
} else {
    config.onError(ERR_AUDIO, "Recorder undefined");
}

The client is working well, I use it for exactly the same task, but using a Java server. I would appreciate if someone could indicate me how to save these audio chunks in a valid file.

Mathieu
  • 8,840
  • 7
  • 32
  • 45

2 Answers2

0

I think that you do not write header in your wav file. To do so,

  • you can write some function to do so see specification here
  • or you can use a dedicaded library, like libsndfile, which is not so complicated to use:

    // instead of fopen, write something like
    SF_INFO info;
    SNDFILE * sf;
    
    info.samplerate = sample_rate;
    info.channels = 1;
    info.sections = 1;
    info.seekable = 0;
    info.frames = 0;
    info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
    
    sf = sf_open(filename, SFM_WRITE, &info);
    

    // instead of fwrite, something like
    sf_write_short(sf, in, len / sizeof(short));
    

    // and instead of fclose
    sf_close(sf);
    
Mathieu
  • 8,840
  • 7
  • 32
  • 45
0

I didn't use libsndfile, but I change something on the client side. This is the current hexdump output:

00000000  52 49 46 46 20 60 00 00  57 41 56 45 66 6d 74 20  |RIFF `..WAVEfmt |
00000010  10 00 00 00 01 00 02 00  44 ac 00 00 10 b1 02 00  |........D.......|
00000020  04 00 10 00 64 61 74 61  00 60 00 00 00 00 00 00  |....data.`......|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00006020  00 00 00 00 00 00 00 00  00 00 00 00 52 49 46 46  |............RIFF|
00006030  20 60 00 00 57 41 56 45  66 6d 74 20 10 00 00 00  | `..WAVEfmt ....|
00006040  01 00 02 00 44 ac 00 00  10 b1 02 00 04 00 10 00  |....D...........|
00006050  64 61 74 61 00 60 00 00  00 00 00 00 00 00 00 00  |data.`..........|
00006060  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
0000c050  00 00 00 00 00 00 00 00  52 49 46 46 20 60 00 00  |........RIFF `..|
0000c060  57 41 56 45 66 6d 74 20  10 00 00 00 01 00 02 00  |WAVEfmt ........|
0000c070  44 ac 00 00 10 b1 02 00  04 00 10 00 64 61 74 61  |D...........data|
0000c080  00 60 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |.`..............|
0000c090  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*

It seems to be wav encoded, but i don't have a content.