Sending audio stream via tcp (Rawbytes)

I am trying to send different data via TCP via “sendRawBytesToAll”, but I have a problem with the sound data I get from ofSoundStream.

The data I get are of the type float but I can’t figure out what the best way of converting it would be.

I am thinking of converting the float to a hex string and somehow load it in to the char vector I am using now (as a pointer) in the “sendRawBytesToAll”.

If I send big TCP packages I don’t know how I would disassemble the hex values (blocks of floats in hex) for converting them to floats again on the other side. Maybe some kind of mark between every float (in hex)?

I am using rawbytes because the project is going to send a lot of data from different analog sources and it would be nice to send all the TCP data by one function and not use the “send (string)” function.

Am I doing it harder then it is?. Is there a simple solution to this problem?

Thank you

the easiest and fastest way is to cast the whole array to an array of char like:

tcpServer.sendRawBytesToAll((char*)soundAray,arraySize*sizeof(float));

and do the same to receive it

Thank you.

I can now send my float vector sound array, but I can’t figure how to cast the chars I get on the client site to a float vector array again.

Can you provide a small example?

is the same:

float * audioBufer;
tcpClient.receiveRawBytes((char*)audioBuffer,bufferSize*sizeof(float));

If I use the pointer instead of the reference like this:
TCPServer.sendRawBytesToAll((char*) *lAudio, sizeof(float));
(I only use a array with one element to make it simpler for myself)

I receive the float value on the client site, but in hex. Can I make some kind of “double” cast (If there is something like this) with the receiveRawBytes object?

If I send my data with the reference:
TCPServer.sendRawBytesToAll((char*) lAudio, sizeof(float));
do I only get the address of the pointer on the client site. (Is there some dereference I do not understand?)

Just to be clear, here’s my code:

ofApp.h - Server

#pragma once

#include "ofMain.h"
#include "ofxNetwork.h"

class ofApp : public ofBaseApp{

public:
    void setup();
    void update();
    void draw();

    void keyPressed(int key);
    void keyReleased(int key);
    void mouseMoved(int x, int y );
    void mouseDragged(int x, int y, int button);
    void mousePressed(int x, int y, int button);
    void mouseReleased(int x, int y, int button);
    void windowResized(int w, int h);
    void dragEvent(ofDragInfo dragInfo);
    void gotMessage(ofMessage msg);
    
    enum TCPState {
        IDLE,
        LOADING_SOUND,
        SENDING_SOUND,
        SEND_ONE
    };
    
    TCPState state;
    
    ofxTCPServer TCPServer;
    ofSoundStream soundStream;
    
    void audioIn(float *input, int bufferSize, int nChannels);
    
    float* lAudio[1];
        
};

ofApp.cpp - Server

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
    
    TCPServer.setup(50002);
    soundStream.setup(this, 0, 2, 44100, 256, 4);

}

//--------------------------------------------------------------
void ofApp::update(){
    
}

//--------------------------------------------------------------
void ofApp::audioIn(float* input, int bufferSize, int nChannels){
    
    for (int i = 0; i < bufferSize && state == LOADING_SOUND; i++) {
        lAudio[i] = &input[i * nChannels];
        *lAudio[i] = fabsf(*lAudio[i]);
        *lAudio[i] = *lAudio[i] * 100.0f;
        state = SEND_ONE;
    }
    
    //temp function
    if (state == SEND_ONE) {
        
        cout << "Float			:" << *lAudio[0] << endl << endl;
        cout << "Pointer			:" << *lAudio << endl;
        cout << "Reference		:" << lAudio << endl << endl;
        
        //Just for check on the client site
        cout << "float in hex		:" << ofToHex(*lAudio[0]) << endl;
        
        
        TCPServer.sendRawBytesToAll((char*) *lAudio, sizeof(float));
    }
    
    state = IDLE;
}

//--------------------------------------------------------------
void ofApp::draw(){

}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
    
    if (key == 's') {
        state = LOADING_SOUND;
    }
}

ofApp.h - Client

#pragma once

#include "ofMain.h"
#include "ofxNetwork.h"

class ofApp : public ofBaseApp{
    
public:
    void setup();
    void update();
    void draw();
    
    void keyPressed(int key);
    void keyReleased(int key);
    void mouseMoved(int x, int y );
    void mouseDragged(int x, int y, int button);
    void mousePressed(int x, int y, int button);
    void mouseReleased(int x, int y, int button);
    void windowResized(int w, int h);
    void dragEvent(ofDragInfo dragInfo);
    void gotMessage(ofMessage msg);
    
    ofxTCPClient TCPClient;
    
    enum tcpState {
        LISTEN,
        RECEIVE
    };
    
    tcpState state;
    
    float* lAudio[1];
};

ofApp.cpp - Client

#include "ofApp.h"
#include <string>

//--------------------------------------------------------------
void ofApp::setup(){
    
    TCPClient.setup("127.0.0.1", 50002);

    if (TCPClient.isConnected()) {
        cout << "ONLINE" << endl;
    }
}

//--------------------------------------------------------------
void ofApp::update(){
    
    if ((int)TCPClient.receiveRawBytes((char *)lAudio,sizeof(float)) > 1) {

        cout << "Pointer Reference			: " << lAudio << endl;
        cout << "Pointer					: " << *lAudio << endl; //The float in hex
    }
}

My server code is a little messy but at this point I just really want to understand how to get it working.

that will actually convert the first value in lAudio to a memory address and try to send whatever is there. if you just want to send one value then:

TCPServer.sendRawBytesToAll((char*) lAudio, sizeof(float));

Maybe I am just missing something.

If I use the reference of lAudio:
I am sending the float: 0.201388 (In hex: 3e4e3894)

ONLINE
Pointer Reference		: 0x2ae6a7c
Pointer					: 0x2904000

If I use the pointer of lAudio:
I am sending the float: 1.03967 (In hex: 3f8513f5)

ONLINE
Pointer Reference		: 0x122fa7c
Pointer					: 0x3f8513f5

If I use the reference I only get some adresses, but if I use the pointer

(char*) *lAudio

I get the data, but in hex.
Sorry if I don’t see the obvious, but I am still a relative new user of C++ and openFramework.

sendRawBytesToAll expects an array so if you try to send anything else it’ll parse it as an array, that is as a memory address and try to read from that memory address. you need to pass an array even if you just want to send one value.

the hex you are seeing is probably because of the way you are printing the value. this:

float value
client.receiveRaw((char*)&value,sizeof(float));
cout << value << endl;

or

float value[1];
client.receiveRaw((char*)value,sizeof(float));
cout << value[0] << endl;

are equivalent and should give you the correct result.

be aware though that with tcp you can’t be sure that you are receiving the full message in one call to receiveRaw so you should check how many bytes it has returned and read the remaining bytes if they are less to what you were trying to read. for 4 bytes (a float) it should be fine though.

Thank you Arturo.

And thank you for the great work in general on openFrameworks!

Hey @arturo, I am running into something like this. Should I be checking the bytes with ofxTCPServer::getNumReceivedBytes(clientID)? This is always returning 0 for me. (OF 0.9.3/Mac)

Here is the scenario I have

I create a TCPServer
Create a ofBuffer
Send the Buffer

 bool didSend = server.sendRawBytes(i, (const char *)buffer.getData(), buffer.size());

So the buffer will make it if it is small but if anything large it will come across incomplete. However if I make the TCPServer blocking I can send huge objects (32MB) without a problem.

Thanks!

you can do something like:

int received = 0;
int expected = ...;
while(received<expected){
    received += receiveRawBytes(receiveBytes + received, expected - received);
}

if you are sending more than one message one after another, at some point you might receive part of the next message in the current buffer so you will need to use a fixed size and then cut the extra bytes or use separator or similar to know where each message ends.

sendRawMsg / receiveRawMsg, takes care of all that without having to worry about the size, adding a terminator…

1 Like

Nice - I must have missed that option. I’ll try that