How to remove the rustling noise when use OpenSLES play pcm audio

712 views
Skip to first unread message

Jack

unread,
Jul 24, 2013, 3:12:43 AM7/24/13
to andro...@googlegroups.com
To get better low-latency effect, I intend to use OpenSLEs interface to play PCM sound forma that just decoded  from the network aac format audio . In the actual i found always with a rustling noise.

discover if the pcm will be stored as file playback, it is normal.

nonuniform
network whether it is playing with a Noise would be the reason?

// this callback handler is called every time a buffer finishes playing
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
    // for streaming playback, replace this test by logic to find and fill the next buffer
    if (!noMoreData) {
        SLresult result;
        int numOfRecords = fread(recorderBuffer, sizeof(short), RECORDER_FRAMES, recordF);
        if (RECORDER_FRAMES != numOfRecords) {
            if (numOfRecords <= 0) {
                noMoreData = 1;
                LOGI(2, "no data for playing");
                (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED);
                fclose(recordF);
                LOGI(2, "player finished playing");
                return;
            }
            LOGE(2, "no more data");
            noMoreData = 1;
        } else {
            LOGI(2, "read %d", numOfRecords);
        }
        result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, recorderBuffer,  RECORDER_FRAMES * sizeof(short));
        // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
        // which for this code example would indicate a programming error
        assert(SL_RESULT_SUCCESS == result);
    } else {
        (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED);
        fclose(recordF);
        LOGI(2, "player finished playing");
    }
}

// create the engine and output mix objects
void naCreateEngine(JNIEnv* env, jclass clazz) {
    SLresult result;

    // create engine
    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
    assert(SL_RESULT_SUCCESS == result);

    // realize the engine
    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    assert(SL_RESULT_SUCCESS == result);

    // get the engine interface, which is needed in order to create other objects
    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
    assert(SL_RESULT_SUCCESS == result);

    // create output mix, with environmental reverb specified as a non-required interface
    const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
    const SLboolean req[1] = {SL_BOOLEAN_FALSE};
    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);
    assert(SL_RESULT_SUCCESS == result);

    // realize the output mix
    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
    assert(SL_RESULT_SUCCESS == result);

   
    // get the environmental reverb interface
    // this could fail if the environmental reverb effect is not available,
    // either because the feature is not present, excessive CPU load, or
    // the required MODIFY_AUDIO_SETTINGS permission was not requested and granted
    result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,
            &outputMixEnvironmentalReverb);
    if (SL_RESULT_SUCCESS == result) {
        result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(
                outputMixEnvironmentalReverb, &reverbSettings);
    }

   
}

// create buffer queue audio player
void createBufferQueueAudioPlayer() {
    SLresult result;
    // configure audio source
    SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1};
    SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 2, 44100*1000,
        SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
        SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, SL_BYTEORDER_LITTLEENDIAN};
    SLDataSource audioSrc = {&loc_bufq, &format_pcm};
    // configure audio sink
    SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
    SLDataSink audioSnk = {&loc_outmix, NULL};
    // create audio player
    const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND, SL_IID_VOLUME};
    const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
            3, ids, req);
    assert(SL_RESULT_SUCCESS == result);
    // realize the player
    result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
    assert(SL_RESULT_SUCCESS == result);
    // get the play interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
    assert(SL_RESULT_SUCCESS == result);
    // get the buffer queue interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
            &bqPlayerBufferQueue);
    if (SL_RESULT_SUCCESS!=result) {
        LOGE(1, "cannot get buffer queue interface");
    }
    assert(SL_RESULT_SUCCESS == result);
    // register callback on the buffer queue
    result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
    assert(SL_RESULT_SUCCESS == result);
    // get the effect send interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND,
            &bqPlayerEffectSend);
    assert(SL_RESULT_SUCCESS == result);
    // get the volume interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
    assert(SL_RESULT_SUCCESS == result);
    LOGI(2, "player created");
}

jboolean startPlaying() {
    SLresult result;
    //open the file to read data
    recordF = fopen("/sdcard/ubitus/audio.pcm", "rb");
    if (NULL == recordF) {
        LOGE(1, "cannot open pcm file to read");
        return JNI_FALSE;
    }
    noMoreData = 0;
    //fill the two buffers for playing first
    int numOfRecords = fread(recorderBuffer, sizeof(short), RECORDER_FRAMES, recordF);
    if (RECORDER_FRAMES != numOfRecords) {
        if (numOfRecords <= 0) {
            LOGI(2, "no data for playing");
            return JNI_TRUE;
        }
        noMoreData = 1;
        LOGE(2, "no more data");
    } else {
        LOGI(2, "read %d", numOfRecords)
    }
    result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, recorderBuffer, RECORDER_FRAMES * sizeof(short));
    if (SL_RESULT_SUCCESS != result) {
        return JNI_FALSE;
    }
    // set the player's state to playing
    result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
    assert(SL_RESULT_SUCCESS == result);
    LOGI(2, "player started playing");
    return JNI_TRUE;
}

Glenn Kasten

unread,
Jul 25, 2013, 10:56:19 AM7/25/13
to andro...@googlegroups.com
I assume that "rustling" is clicks and pops?
If so, these are probably underruns.
If you haven't already, please watch video
It discusses the causes and solutions for underruns.
For example, one thing that looks suspicious is
the call to fread. fread, especially from flash filesystem,
does not give predictable performance.
Also check your sample rate and buffer size as per the video.
If the "rustling" you hear is not clicks and pops (underruns),
then please include a URL that points to a recording taken from the line output jack.
It's preferable to take the recording as "raw" as possible ...
at the same sample rate as the device, 16-bit PCM rather than MPC/AAC, etc.
This makes it easier to do analysis.

Mike Healey

unread,
Jul 26, 2013, 5:02:36 AM7/26/13
to andro...@googlegroups.com
Hi Jack, are you sure there is no header information in your .pcm files, e.g. the data is including WAV headers? If it works when playing from file but not when you read the data yourself and supply if directly then perhaps in the former case the header is being parsed and you need to do the same when doing file reading yourself.
Reply all
Reply to author
Forward
0 new messages