1

I'm trying to make app that transmits SuperpoweredAndroidAudioIO buffer from one android device to another. With the following code I've managed to send and receive short int buffer from the audio callback. However on the receiving side sound gets very distorted during playback.

Note: For brevity I have not included some code that doesen't seem to have to do with issue, including socket initialisation related functions. If needed I can add the code.

Sending side:

Mic.cpp

static bool SendBuffer(
    int sd,
    sockaddr_in address,
    short int *buffer,
    size_t bufferSize) {

// Send data buffer to the socket
ssize_t sentSize = sendto(sd, 
    buffer, 
    bufferSize,
    0,  
    (struct sockaddr*)&address,
    sizeof address);

    // If send is failed
    if (sentSize == -1){
        __android_log_print(ANDROID_LOG_INFO, "Sent size ", "%i error %i", 
        sentSize , errno);
    }
    else if (sentSize > 0) {
    __android_log_print(ANDROID_LOG_INFO, "DatagramSent : ", "%hi size: %hi", 
    buffer, sentSize);
    }
    return true;
}

// audio callback
static bool micProcessing(
    void *clientdata,
    short int *audioInputOutput, 
    int numberOfSamples, 
    int __unused samplerate) {

    return SendBuffer(micSocket, dsocket, audioInputOutput, numberOfSamples);

}

// Constructor
Mic::Mic(JNIEnv *env,
    unsigned int samplerate,
    unsigned int buffersize,
    unsigned int port){

    micSocket = NewUdpSocket(env);
    dsocket = initDestinationSocket(port); // where to send
    __android_log_write(ANDROID_LOG_DEBUG, "Sockets", "initialised");

    // init IO
    microphone =  new SuperpoweredAndroidAudioIO(samplerate, 
                                                 buffersize, 
                                                 true, 
                                                 false, 
                                                 micProcessing,
                                                 this, 
                                                 -1, 
                                                 SL_ANDROID_STREAM_MEDIA, 
                                                 buffersize*2);

    __android_log_write(ANDROID_LOG_DEBUG, "Mic", "initialised");
}

Receiving side consists of 2 parts: Mixer and Channel

Mixer.cpp

//audio callback
static bool mainprocess(
    void *clientdata, 
    short int *audioInputOutput, 
    int numberOfSamples, 
    int __unused samplerate) {

    return ((Mixer*)clientdata)->processMain(audioInputOutput, numberOfSamples);
}
// Setting up Mixer
Mixer::Mixer(JNIEnv *env,unsigned int samplerate, unsigned int buffersize) {
    //Short int buffers for recieving
    channel1 = new Channel(samplerate,buffersize);
    //output buffer
    outputFloat = ((float *)memalign(16, (buffersize + 16) * sizeof(float) * 2));

    //volumes
    outputLevel = 0.5f;

    channel1level = 0.2f;
    channel2level = 0.2f;
    channel3level = 0.2f;
    channel4level = 0.2f;

    mainmixer = new SuperpoweredMonoMixer();
    __android_log_print(ANDROID_LOG_INFO, "Mixer", " Created");

    main = new SuperpoweredAndroidAudioIO(
        samplerate,
        buffersize, 
        false, 
        true, 
        mainprocess,
        this,
        -1, 
        SL_ANDROID_STREAM_MEDIA, 
        buffersize*2);

    __android_log_write(ANDROID_LOG_INFO, "Main AudioIO created", " ");
        main->stop();

        SuperpoweredCPU::setSustainedPerformanceMode(true); // Prevents CPU drops
}
// processing.
bool Mixer::processMain(short int *outputbuffer, unsigned int numberOfSamples{
    // a bit awkward
    channel1->returnFloatBuffer();
    inputs[0] = channel1->floatBuffer;

    inputs[1] = NULL;
    inputs[2] = NULL;
    inputs[3] = NULL;

    __android_log_print(ANDROID_LOG_INFO, "Channels are inside", " of mixer");
    inputLevels[0] = channel1level;
    inputLevels[1] = channel2level;
    inputLevels[2] = channel3level;
    inputLevels[3] = channel4level;

    mainmixer->process(inputs,
                       outputFloat,
                       inputLevels, 
                       outputLevel,
                       numberOfSamples);

    SuperpoweredFloatToShortInt(outputFloat, outputbuffer, numberOfSamples);
    return true;
}

Channel.cpp

//receiving buffer

static bool  ReceiveDatagramFromSocket(int sd, short int *buffer, size_t bufferSize) {

    ssize_t  recvSize = recvfrom(sd, buffer, bufferSize, 0, NULL, NULL);

    if (-1 == recvSize){ // If failed
        __android_log_print(ANDROID_LOG_INFO, "receive failed", " %i  ", errno);
    }
    else {
        // If data is received
        if (recvSize > 0) {
        __android_log_print(ANDROID_LOG_INFO, "Received"," %i bytes: %hi", recvSize, buffer);
        }
    }
    return true;
}
// init channel
Channel::Channel(unsigned int samplerate, unsigned int buffersize){
    socketIn = NewUdpSocket();
    BindSocketToPort(socketIn);

    samplerRate = samplerate;
    bufferSize = buffersize;

    shortIntBuffer = (short int *)malloc((buffersize + 16) * sizeof(short int)*4);
    floatBuffer = (float *)memalign(16, (buffersize + 16) * sizeof(float) * 2);

    bandEQ = new Superpowered3BandEQ(samplerate);
    bandEQ->enable(true);
    __android_log_print(ANDROID_LOG_INFO, "Channel ", "created");
}

// this function is called from Mixer.cpp
void Channel::returnFloatBuffer(){
    ReceiveDatagramFromSocket(socketIn, shortIntBuffer, bufferSize);
    Converting the 16-bit integer samples to 32-bit floating point.
    SuperpoweredShortIntToFloat(shortIntBuffer, floatBuffer, bufferSize, 1);
    bandEQ->process(floatBuffer, floatBuffer, bufferSize );
    __android_log_print(ANDROID_LOG_INFO, "EQ", " processing");
}

At first I thought that because AudioIO on both sided get initialised with different buffer sizes (different devices 240 and 512), but then I tried to hardcode 512 into both of them but it didn't help.

I also tried to increase buffer sizes in sendto() and recvfrom() up to 4096 and it made sound more recognizable but still too distorted.

I should also add that I'm a newbie in C++ and I stuck to 'naive' and 'whatever works' approaches which got me this far.

I want to understand whether I'm on the right track and what approach should I take in order to transmit audio without distortion.

1 Answers1

0

There are two major problems with your approach:

  • Blocking functions, such as networking should be avoided from the audio processing callback. You need to perform networking (on both sides) from a different thread, and you need some buffering between the audio processing callback and the network thread to pass audio.

  • You need to "packetize" the transfers, you need to handle network packets on both sides. Network transfer is not fast nor reliable, so you need clever mechanisms to handle this.

In general, the implementation for such audio transfer is much, much more complex to your current code.

Gabor Szanto
  • 1,329
  • 8
  • 12