0

I want to send binary audio data to IBM watson STT service trhough websocket connection. I have successfully made the connection and now trying to send the data in following format:

{
  "action":"start",
  "content-type": "audio/l16;rate=44100"
}
<binary audio data>
{
  "action":"stop"
}

for this: I am reading a raw audio file (extn .pcm) as below

#include <string>
#include <fstream>

ifstream fin;
string binarydata, bdataline;

fin.open("/home/rohan/TestFile.pcm", ios::binary | ios::in);

while (fin) {
    // Read a Line from File
    getline(fin, bdataline);
    binarydata = binarydata + bdataline;
}

Question 1: I am not sure if I am reading the binary data correctly. Should the datatype of the binarydata be string?

Next to send the data on boost websocket (after handshake) I have followed this routine

void on_handshake(beast::error_code ec)
    {
         if(ec)
             return fail(ec, "handshake");

         // Send the Start message
         ws_.async_write(net::buffer("{\"action\":\"start\",\"content-type\": \"audio/l16;rate=44100\"}"), bind(&session::on_start, shared_from_this(), placeholders::_1));
    }

void on_start(beast::error_code ec)
    {
        if(ec)
            return fail(ec, "write:start");

        ws_.async_write(net::buffer(binarydata), bind(&session::on_binarysent, shared_from_this(), placeholders::_1));
    }

void on_binarysent(beast::error_code ec)
    {
        if(ec)
            return fail(ec, "write:Msg");

        ws_.async_write(net::buffer("{\"action\":\"stop\"}"), bind(&session::on_write, shared_from_this(), placeholders::_1));
    }


void on_write( beast::error_code ec) //,
    {
        if(ec)
            return fail(ec, "write:end");

        ws_.async_read(buffer_, bind(&session::on_start, shared_from_this(), placeholders::_1));
    }

The program does not show any output and exits with

write:start: The WebSocket stream was gracefully closed at both endpoints

Question 2: Whether the data is going correctly as expected? How to check that? (expected : See this link)

How is the websocket getting closed without sending close command?

UPDATED:

void on_start(beast::error_code ec)
    {
        if(ec)
            return fail(ec, "write:start");



ifstream infile("/home/rohan/TestFile.pcm", ios::in | ios::binary);
    streampos FileSize;

    if (infile) {
        // Get the size of the file
        infile.seekg(0, ios::end);
        FileSize = infile.tellg();
        infile.seekg(0, ios::beg);
    }
    char binarydata[(size_t)FileSize];
        ws_.binary(true);

        // Send binary data
        ws_.async_write(net::buffer(binarydata, sizeof(binarydata)), bind(&session::on_binarysent, shared_from_this(), placeholders::_1));
    }
  • A great way to show respect for other peoples' time is to follow the directions in the Beast documentation with respect to familiarity with Asio. These questions have nothing to do with Beast. – Vinnie Falco Dec 26 '18 at 17:33
  • Hi @VinnieFalco, I understand that it might feel cumbersome to teach a rookie about the concepts (which you have mastered). I can understand that my questions might fall off-track. I sincerely feel grateful for your help though. I will try to keep my posts limited henceforth. _PS: I'm just a rookie trying to survive in technologically advanced world._ –  Dec 28 '18 at 07:26

2 Answers2

2

Answer 1:

With respect to the websocket portion of the question, you should make sure that you are sending binary messages by calling websocket::stream::binary(true). See:

https://www.boost.org/doc/libs/1_69_0/libs/beast/doc/html/beast/ref/boost__beast__websocket__stream/binary/overload1.html

Answer 2:

From: https://www.boost.org/doc/libs/1_69_0/libs/beast/doc/html/beast/using_websocket/control_frames.html#beast.using_websocket.control_frames.close_frames

"When a close frame is received during a read operation, the implementation will automatically respond with a close frame and then shut down the underlying connection before returning. In this case, the read operation will complete with the code error::closed. This indicates to the caller that the connection has been closed cleanly."

Answer 3 (Updated)

You wrote:

vector<char> binarydata(istreambuf_iterator<char {infile}, {});

You are using a local variable as the buffer for an asynchronous operation. The caller is responsible for ensuring that the lifetime of the buffers extends at least until the completion handler is invoked. Your code produces undefined behavior.

The Beast documentation makes this clear:

"This library is for programmers familiar with Boost.Asio. Users who wish to use asynchronous interfaces should already know how to create concurrent network programs using callbacks or coroutines."

(https://www.boost.org/doc/libs/1_69_0/libs/beast/doc/html/beast/introduction.html)

If you are not already proficient in working with Asio, then I suggest you put your current project on pause and study Asio so that you will be able to use Beast effectively. Otherwise you will encounter obstacles at every step of the path.

Vinnie Falco
  • 5,173
  • 28
  • 43
  • I have updated the question as per your suggestion. With these updates the program is not reaching at the point where the connection is being closed "gracefully". Instead it is exiting with value `-1`. Is the calling function correctly written? `ws_.binary(true);` –  Dec 26 '18 at 13:43
  • I have updated the post. Please have a look. `(net::buffer(binarydata,sizeof(binarydata))` now the program exits with value `0` –  Dec 26 '18 at 14:07
-1

You cannot use string to store binary data, use char data[] with int length or std::vector<char> or whatever.

Reading binary data shouldn't be done with getline() as soon as there are not lines in binary files.

You can use something like:

std::ifstream f("/home/rohan/TestFile.pcm", std::ios::binary);
std::vector<char> v(std::istreambuf_iterator<char>{f}, {});
grapes
  • 8,185
  • 1
  • 19
  • 31
  • I have updated the post. I have made changes as you'd see. I have omitted the earlier file reading way *(the incorrect one)*. Thanks for the correction. Is there a way to see if the `binarydata` holds binary data? –  Dec 26 '18 at 13:46
  • What do you mean "holds binary data"? Any data can be binary, but not any - text. So whatever there is in `binarydata`, it is binary data. Sometimes you can make assumptions that the data is text, but they are not strict and depend on possible text encodings. – grapes Dec 26 '18 at 14:04
  • Thanks for the clarification :) –  Dec 26 '18 at 14:09
  • 1
    `std::string` is more than capable of holding binary data, including nulls. – Vinnie Falco Dec 26 '18 at 17:28
  • I have used the char array to get the binary data. You can check how I have read the binary file in the updated post. This is working for me. –  Dec 28 '18 at 08:41