C++程序  |  674行  |  24.31 KB

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


////////////////////////////////////////////
/// Actual sles functions.


// Test program to record from default audio input and playback to default audio output.
// It will generate feedback (Larsen effect) if played through on-device speakers,
// or acts as a delay if played through headset.

#include "sles.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>

#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int slesInit(sles_data ** ppSles, int samplingRate, int frameCount, int micSource,
             int numFramesToIgnore) {
    int status = SLES_FAIL;
    if (ppSles != NULL) {
        sles_data * pSles = (sles_data*) calloc(1, sizeof (sles_data));

        SLES_PRINTF("malloc %zu bytes at %p", sizeof(sles_data), pSles);
        *ppSles = pSles;
        if (pSles != NULL)
        {
            SLES_PRINTF("creating server. Sampling rate =%d, frame count = %d",samplingRate,
                    frameCount);
            status = slesCreateServer(pSles, samplingRate, frameCount, micSource,
                                      numFramesToIgnore);
            SLES_PRINTF("slesCreateServer =%d", status);
        }
    }
    return status;
}
int slesDestroy(sles_data ** ppSles) {
    int status = SLES_FAIL;
    if (ppSles != NULL) {
        slesDestroyServer(*ppSles);

        if (*ppSles != NULL)
        {
            free(*ppSles);
            *ppSles = 0;
        }
        status = SLES_SUCCESS;
    }
    return status;
}

#define ASSERT_EQ(x, y) do { if ((x) == (y)) ; else { fprintf(stderr, "0x%x != 0x%x\n", \
        (unsigned) (x), (unsigned) (y)); assert((x) == (y)); } } while (0)


// Called after audio recorder fills a buffer with data
static void recorderCallback(SLAndroidSimpleBufferQueueItf caller __unused, void *context) {
    sles_data *pSles = (sles_data*) context;
    if (pSles != NULL) {



        SLresult result;

        pthread_mutex_lock(&(pSles->mutex));
        //ee  SLES_PRINTF("<R");

        // We should only be called when a recording buffer is done
        assert(pSles->rxFront <= pSles->rxBufCount);
        assert(pSles->rxRear <= pSles->rxBufCount);
        assert(pSles->rxFront != pSles->rxRear);
        char *buffer = pSles->rxBuffers[pSles->rxFront];

        // Remove buffer from record queue
        if (++pSles->rxFront > pSles->rxBufCount) {
            pSles->rxFront = 0;
        }

        // Throw out first frames
        if (pSles->numFramesToIgnore) {
            SLuint32 framesToErase = pSles->numFramesToIgnore;
            if (framesToErase > pSles->bufSizeInFrames) {
                framesToErase = pSles->bufSizeInFrames;
            }
            pSles->numFramesToIgnore -= framesToErase;
            // FIXME: this assumes each sample is a short
            memset(buffer, 0, framesToErase * pSles->channels * sizeof(short));
        }

        ssize_t actual = audio_utils_fifo_write(&(pSles->fifo), buffer,
                (size_t) pSles->bufSizeInFrames);
        if (actual != (ssize_t) pSles->bufSizeInFrames) {
            write(1, "?", 1);
        }

        // This is called by a realtime (SCHED_FIFO) thread,
        // and it is unsafe to do I/O as it could block for unbounded time.
        // Flash filesystem is especially notorious for blocking.
        if (pSles->fifo2Buffer != NULL) {
            actual = audio_utils_fifo_write(&(pSles->fifo2), buffer,
                    (size_t) pSles->bufSizeInFrames);
            if (actual != (ssize_t) pSles->bufSizeInFrames) {
                write(1, "?", 1);
            }
        }

        // Enqueue this same buffer for the recorder to fill again.
        result = (*(pSles->recorderBufferQueue))->Enqueue(pSles->recorderBufferQueue, buffer,
                pSles->bufSizeInBytes);
        ASSERT_EQ(SL_RESULT_SUCCESS, result);

        // Update our model of the record queue
        SLuint32 rxRearNext = pSles->rxRear+1;
        if (rxRearNext > pSles->rxBufCount) {
            rxRearNext = 0;
        }
        assert(rxRearNext != pSles->rxFront);
        pSles->rxBuffers[pSles->rxRear] = buffer;
        pSles->rxRear = rxRearNext;



        //ee  SLES_PRINTF("r>");
        pthread_mutex_unlock(&(pSles->mutex));

    } //pSles not null
}


// Called after audio player empties a buffer of data
static void playerCallback(SLBufferQueueItf caller __unused, void *context) {
    sles_data *pSles = (sles_data*) context;
    if (pSles != NULL) {

        SLresult result;

        pthread_mutex_lock(&(pSles->mutex));
        //ee  SLES_PRINTF("<P");

        // Get the buffer that just finished playing
        assert(pSles->txFront <= pSles->txBufCount);
        assert(pSles->txRear <= pSles->txBufCount);
        assert(pSles->txFront != pSles->txRear);
        char *buffer = pSles->txBuffers[pSles->txFront];
        if (++pSles->txFront > pSles->txBufCount) {
            pSles->txFront = 0;
        }


        ssize_t actual = audio_utils_fifo_read(&(pSles->fifo), buffer, pSles->bufSizeInFrames);
        if (actual != (ssize_t) pSles->bufSizeInFrames) {
            write(1, "/", 1);
            // on underrun from pipe, substitute silence
            memset(buffer, 0, pSles->bufSizeInFrames * pSles->channels * sizeof(short));
        }

        if (pSles->injectImpulse == -1) {
            // Experimentally, a single frame impulse was insufficient to trigger feedback.
            // Also a Nyquist frequency signal was also insufficient, probably because
            // the response of output and/or input path was not adequate at high frequencies.
            // This short burst of a few cycles of square wave at Nyquist/4 was found to work well.
            for (unsigned i = 0; i < pSles->bufSizeInFrames / 8; i += 8) {
                for (int j = 0; j < 8; j++) {
                    for (unsigned k = 0; k < pSles->channels; k++) {
                        ((short *)buffer)[(i+j)*pSles->channels+k] = j < 4 ? 0x7FFF : 0x8000;
                    }
                }
            }
            pSles->injectImpulse = 0;
        }

        // Enqueue the filled buffer for playing
        result = (*(pSles->playerBufferQueue))->Enqueue(pSles->playerBufferQueue, buffer,
                pSles->bufSizeInBytes);
        ASSERT_EQ(SL_RESULT_SUCCESS, result);

        // Update our model of the player queue
        assert(pSles->txFront <= pSles->txBufCount);
        assert(pSles->txRear <= pSles->txBufCount);
        SLuint32 txRearNext = pSles->txRear+1;
        if (txRearNext > pSles->txBufCount) {
            txRearNext = 0;
        }
        assert(txRearNext != pSles->txFront);
        pSles->txBuffers[pSles->txRear] = buffer;
        pSles->txRear = txRearNext;


        //ee    SLES_PRINTF("p>");
        pthread_mutex_unlock(&(pSles->mutex));

    } //pSles not null
}

int slesCreateServer(sles_data *pSles, int samplingRate, int frameCount,
                     int micSource, int numFramesToIgnore) {
    int status = SLES_FAIL;

    if (pSles == NULL) {
        return status;
    }

    //        adb shell slesTest_feedback -r1 -t1 -s48000 -f240 -i300 -e3 -o/sdcard/log.wav
    //            r1 and t1 are the receive and transmit buffer counts, typically 1
    //            s is the sample rate, typically 48000 or 44100
    //            f is the frame count per buffer, typically 240 or 256
    //            i is the number of milliseconds before impulse.  You may need to adjust this.
    //            e is number of seconds to record
    //            o is output .wav file name


    //        // default values
    //        SLuint32 rxBufCount = 1;     // -r#
    //        SLuint32 txBufCount = 1;     // -t#
    //        SLuint32 bufSizeInFrames = 240;  // -f#
    //        SLuint32 channels = 1;       // -c#
    //        SLuint32 sampleRate = 48000; // -s#
    //        SLuint32 exitAfterSeconds = 3; // -e#
    //        SLuint32 freeBufCount = 0;   // calculated
    //        SLuint32 bufSizeInBytes = 0; // calculated
    //        int injectImpulse = 300; // -i#i
    //
    //        // Storage area for the buffer queues
    //        char **rxBuffers;
    //        char **txBuffers;
    //        char **freeBuffers;
    //
    //        // Buffer indices
    //        SLuint32 rxFront;    // oldest recording
    //        SLuint32 rxRear;     // next to be recorded
    //        SLuint32 txFront;    // oldest playing
    //        SLuint32 txRear;     // next to be played
    //        SLuint32 freeFront;  // oldest free
    //        SLuint32 freeRear;   // next to be freed
    //
    //        audio_utils_fifo fifo; //(*)
    //        SLAndroidSimpleBufferQueueItf recorderBufferQueue;
    //        SLBufferQueueItf playerBufferQueue;

    // default values
    pSles->rxBufCount = 1;     // -r#
    pSles->txBufCount = 1;     // -t#
    pSles->bufSizeInFrames = frameCount;//240;  // -f#
    pSles->channels = 1;       // -c#
    pSles->sampleRate = samplingRate;//48000; // -s#
    pSles->exitAfterSeconds = 3; // -e#
    pSles->freeBufCount = 0;   // calculated
    pSles->bufSizeInBytes = 0; // calculated
    pSles->injectImpulse = 300; // -i#i

    if (numFramesToIgnore > 0) {
        pSles->numFramesToIgnore = numFramesToIgnore;
    } else {
        pSles->numFramesToIgnore = 0;
    }

    // Storage area for the buffer queues
    //        char **rxBuffers;
    //        char **txBuffers;
    //        char **freeBuffers;

    // Buffer indices
/*
    pSles->rxFront;    // oldest recording
    pSles->rxRear;     // next to be recorded
    pSles->txFront;    // oldest playing
    pSles->txRear;     // next to be played
    pSles->freeFront;  // oldest free
    pSles->freeRear;   // next to be freed

    pSles->fifo; //(*)
*/
    pSles->fifo2Buffer = NULL;

    // compute total free buffers as -r plus -t
    pSles->freeBufCount = pSles->rxBufCount + pSles->txBufCount;
    // compute buffer size
    pSles->bufSizeInBytes = pSles->channels * pSles->bufSizeInFrames * sizeof(short);

    // Initialize free buffers
    pSles->freeBuffers = (char **) calloc(pSles->freeBufCount+1, sizeof(char *));
    unsigned j;
    for (j = 0; j < pSles->freeBufCount; ++j) {
        pSles->freeBuffers[j] = (char *) malloc(pSles->bufSizeInBytes);
    }
    pSles->freeFront = 0;
    pSles->freeRear = pSles->freeBufCount;
    pSles->freeBuffers[j] = NULL;

    // Initialize record queue
    pSles->rxBuffers = (char **) calloc(pSles->rxBufCount+1, sizeof(char *));
    pSles->rxFront = 0;
    pSles->rxRear = 0;

    // Initialize play queue
    pSles->txBuffers = (char **) calloc(pSles->txBufCount+1, sizeof(char *));
    pSles->txFront = 0;
    pSles->txRear = 0;

    size_t frameSize = pSles->channels * sizeof(short);
#define FIFO_FRAMES 1024
    pSles->fifoBuffer = new short[FIFO_FRAMES * pSles->channels];
    audio_utils_fifo_init(&(pSles->fifo), FIFO_FRAMES, frameSize, pSles->fifoBuffer);

    //        SNDFILE *sndfile;
    //        if (outFileName != NULL) {
    // create .wav writer
    //            SF_INFO info;
    //            info.frames = 0;
    //            info.samplerate = sampleRate;
    //            info.channels = channels;
    //            info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
    //            sndfile = sf_open(outFileName, SFM_WRITE, &info);
    //            if (sndfile != NULL) {
#define FIFO2_FRAMES 65536
    pSles->fifo2Buffer = new short[FIFO2_FRAMES * pSles->channels];
    audio_utils_fifo_init(&(pSles->fifo2), FIFO2_FRAMES, frameSize, pSles->fifo2Buffer);
    //            } else {
    //                fprintf(stderr, "sf_open failed\n");
    //            }
    //        } else {
    //            sndfile = NULL;
    //        }

    SLresult result;

    // create engine
    result = slCreateEngine(&(pSles->engineObject), 0, NULL, 0, NULL, NULL);
    ASSERT_EQ(SL_RESULT_SUCCESS, result);
    result = (*(pSles->engineObject))->Realize(pSles->engineObject, SL_BOOLEAN_FALSE);
    ASSERT_EQ(SL_RESULT_SUCCESS, result);
    SLEngineItf engineEngine;
    result = (*(pSles->engineObject))->GetInterface(pSles->engineObject, SL_IID_ENGINE,
            &engineEngine);
    ASSERT_EQ(SL_RESULT_SUCCESS, result);

    // create output mix
    result = (*engineEngine)->CreateOutputMix(engineEngine, &(pSles->outputmixObject), 0, NULL,
            NULL);
    ASSERT_EQ(SL_RESULT_SUCCESS, result);
    result = (*(pSles->outputmixObject))->Realize(pSles->outputmixObject, SL_BOOLEAN_FALSE);
    ASSERT_EQ(SL_RESULT_SUCCESS, result);

    // create an audio player with buffer queue source and output mix sink
    SLDataSource audiosrc;
    SLDataSink audiosnk;
    SLDataFormat_PCM pcm;
    SLDataLocator_OutputMix locator_outputmix;
    SLDataLocator_BufferQueue locator_bufferqueue_tx;
    locator_bufferqueue_tx.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
    locator_bufferqueue_tx.numBuffers = pSles->txBufCount;
    locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
    locator_outputmix.outputMix = pSles->outputmixObject;
    pcm.formatType = SL_DATAFORMAT_PCM;
    pcm.numChannels = pSles->channels;
    pcm.samplesPerSec = pSles->sampleRate * 1000;
    pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
    pcm.containerSize = 16;
    pcm.channelMask = pSles->channels == 1 ? SL_SPEAKER_FRONT_CENTER :
            (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
    pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
    audiosrc.pLocator = &locator_bufferqueue_tx;
    audiosrc.pFormat = &pcm;
    audiosnk.pLocator = &locator_outputmix;
    audiosnk.pFormat = NULL;
    pSles->playerObject = NULL;
    pSles->recorderObject = NULL;
    SLInterfaceID ids_tx[1] = {SL_IID_BUFFERQUEUE};
    SLboolean flags_tx[1] = {SL_BOOLEAN_TRUE};
    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &(pSles->playerObject),
            &audiosrc, &audiosnk, 1, ids_tx, flags_tx);
    if (SL_RESULT_CONTENT_UNSUPPORTED == result) {
        fprintf(stderr, "Could not create audio player (result %x), check sample rate\n",
                result);
        SLES_PRINTF("ERROR: Could not create audio player (result %x), check sample rate\n",
                result);
        goto cleanup;
    }
    ASSERT_EQ(SL_RESULT_SUCCESS, result);
    result = (*(pSles->playerObject))->Realize(pSles->playerObject, SL_BOOLEAN_FALSE);
    ASSERT_EQ(SL_RESULT_SUCCESS, result);
    SLPlayItf playerPlay;
    result = (*(pSles->playerObject))->GetInterface(pSles->playerObject, SL_IID_PLAY,
            &playerPlay);
    ASSERT_EQ(SL_RESULT_SUCCESS, result);
    result = (*(pSles->playerObject))->GetInterface(pSles->playerObject, SL_IID_BUFFERQUEUE,
            &(pSles->playerBufferQueue));
    ASSERT_EQ(SL_RESULT_SUCCESS, result);
    result = (*(pSles->playerBufferQueue))->RegisterCallback(pSles->playerBufferQueue,
            playerCallback, pSles);
    ASSERT_EQ(SL_RESULT_SUCCESS, result);

    // Enqueue some zero buffers for the player
    for (j = 0; j < pSles->txBufCount; ++j) {

        // allocate a free buffer
        assert(pSles->freeFront != pSles->freeRear);
        char *buffer = pSles->freeBuffers[pSles->freeFront];
        if (++pSles->freeFront > pSles->freeBufCount) {
            pSles->freeFront = 0;
        }

        // put on play queue
        SLuint32 txRearNext = pSles->txRear + 1;
        if (txRearNext > pSles->txBufCount) {
            txRearNext = 0;
        }
        assert(txRearNext != pSles->txFront);
        pSles->txBuffers[pSles->txRear] = buffer;
        pSles->txRear = txRearNext;
        result = (*(pSles->playerBufferQueue))->Enqueue(pSles->playerBufferQueue,
                buffer, pSles->bufSizeInBytes);
        ASSERT_EQ(SL_RESULT_SUCCESS, result);
    }

    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
    ASSERT_EQ(SL_RESULT_SUCCESS, result);

    // Create an audio recorder with microphone device source and buffer queue sink.
    // The buffer queue as sink is an Android-specific extension.

    SLDataLocator_IODevice locator_iodevice;
    SLDataLocator_AndroidSimpleBufferQueue locator_bufferqueue_rx;
    locator_iodevice.locatorType = SL_DATALOCATOR_IODEVICE;
    locator_iodevice.deviceType = SL_IODEVICE_AUDIOINPUT;
    locator_iodevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
    locator_iodevice.device = NULL;
    audiosrc.pLocator = &locator_iodevice;
    audiosrc.pFormat = NULL;
    locator_bufferqueue_rx.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
    locator_bufferqueue_rx.numBuffers = pSles->rxBufCount;
    audiosnk.pLocator = &locator_bufferqueue_rx;
    audiosnk.pFormat = &pcm;
    {
        SLInterfaceID ids_rx[2] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
                SL_IID_ANDROIDCONFIGURATION};
        SLboolean flags_rx[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
        result = (*engineEngine)->CreateAudioRecorder(engineEngine, &(pSles->recorderObject),
                &audiosrc, &audiosnk, 2, ids_rx, flags_rx);
        if (SL_RESULT_SUCCESS != result) {
            fprintf(stderr, "Could not create audio recorder (result %x), "
                    "check sample rate and channel count\n", result);
            status = SLES_FAIL;

            SLES_PRINTF("ERROR: Could not create audio recorder (result %x), "
                    "check sample rate and channel count\n", result);
            goto cleanup;
        }
    }
    ASSERT_EQ(SL_RESULT_SUCCESS, result);

    {
        /* Get the Android configuration interface which is explicit */
        SLAndroidConfigurationItf configItf;
        result = (*(pSles->recorderObject))->GetInterface(pSles->recorderObject,
                SL_IID_ANDROIDCONFIGURATION, (void*)&configItf);
        ASSERT_EQ(SL_RESULT_SUCCESS, result);
        SLuint32 presetValue = micSource;
        /* Use the configuration interface to configure the recorder before it's realized */
        if (presetValue != SL_ANDROID_RECORDING_PRESET_NONE) {
            result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET,
                    &presetValue, sizeof(SLuint32));
            ASSERT_EQ(SL_RESULT_SUCCESS, result);
        }

    }

    result = (*(pSles->recorderObject))->Realize(pSles->recorderObject, SL_BOOLEAN_FALSE);
    ASSERT_EQ(SL_RESULT_SUCCESS, result);
    SLRecordItf recorderRecord;
    result = (*(pSles->recorderObject))->GetInterface(pSles->recorderObject, SL_IID_RECORD,
            &recorderRecord);
    ASSERT_EQ(SL_RESULT_SUCCESS, result);
    result = (*(pSles->recorderObject))->GetInterface(pSles->recorderObject,
            SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &(pSles->recorderBufferQueue));
    ASSERT_EQ(SL_RESULT_SUCCESS, result);
    result = (*(pSles->recorderBufferQueue))->RegisterCallback(pSles->recorderBufferQueue,
            recorderCallback, pSles);
    ASSERT_EQ(SL_RESULT_SUCCESS, result);

    // Enqueue some empty buffers for the recorder
    for (j = 0; j < pSles->rxBufCount; ++j) {

        // allocate a free buffer
        assert(pSles->freeFront != pSles->freeRear);
        char *buffer = pSles->freeBuffers[pSles->freeFront];
        if (++pSles->freeFront > pSles->freeBufCount) {
            pSles->freeFront = 0;
        }

        // put on record queue
        SLuint32 rxRearNext = pSles->rxRear + 1;
        if (rxRearNext > pSles->rxBufCount) {
            rxRearNext = 0;
        }
        assert(rxRearNext != pSles->rxFront);
        pSles->rxBuffers[pSles->rxRear] = buffer;
        pSles->rxRear = rxRearNext;
        result = (*(pSles->recorderBufferQueue))->Enqueue(pSles->recorderBufferQueue,
                buffer, pSles->bufSizeInBytes);
        ASSERT_EQ(SL_RESULT_SUCCESS, result);
    }

    // Kick off the recorder
    result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
    ASSERT_EQ(SL_RESULT_SUCCESS, result);

    // Tear down the objects and exit
    status = SLES_SUCCESS;
    cleanup:
    SLES_PRINTF("Finished initialization with status: %d", status);

    return status;
}

int slesProcessNext(sles_data *pSles, double *pSamples, long maxSamples) {
    //int status = SLES_FAIL;

    SLES_PRINTF("slesProcessNext: pSles = %p, currentSample: %p,  maxSamples = %ld", pSles,
            pSamples, maxSamples);

    int samplesRead = 0;

    int currentSample = 0;
    double *pCurrentSample = pSamples;
    int maxValue = 32768;

    if (pSles == NULL) {
        return samplesRead;
    }

    SLresult result;
    for (int i = 0; i < 10; i++) {
        usleep(100000);
        if (pSles->fifo2Buffer != NULL) {
            for (;;) {
                short buffer[pSles->bufSizeInFrames * pSles->channels];
                ssize_t actual = audio_utils_fifo_read(&(pSles->fifo2), buffer,
                        pSles->bufSizeInFrames);
                if (actual <= 0)
                    break;
                {
                    for (int jj =0; jj<actual && currentSample < maxSamples; jj++) {
                        *(pCurrentSample++) = ((double)buffer[jj])/maxValue;
                        currentSample++;
                    }
                }
                samplesRead +=actual;
            }
        }
        if (pSles->injectImpulse > 0) {
            if (pSles->injectImpulse <= 100) {
                pSles->injectImpulse = -1;
                write(1, "I", 1);
            } else {
                if ((pSles->injectImpulse % 1000) < 100) {
                    write(1, "i", 1);
                }
                pSles->injectImpulse -= 100;
            }
        } else if (i == 9) {
            write(1, ".", 1);
        }
    }
    SLBufferQueueState playerBQState;
    result = (*(pSles->playerBufferQueue))->GetState(pSles->playerBufferQueue,
            &playerBQState);
    ASSERT_EQ(SL_RESULT_SUCCESS, result);
    SLAndroidSimpleBufferQueueState recorderBQState;
    result = (*(pSles->recorderBufferQueue))->GetState(pSles->recorderBufferQueue,
            &recorderBQState);
    ASSERT_EQ(SL_RESULT_SUCCESS, result);

    SLES_PRINTF("End of slesProcessNext: pSles = %p, samplesRead = %d, maxSamples= %ld", pSles,
            samplesRead, maxSamples);

    return samplesRead;
}

int slesDestroyServer(sles_data *pSles) {
    int status = SLES_FAIL;

    SLES_PRINTF("Start slesDestroyServer: pSles = %p", pSles);
    if (pSles == NULL) {
        return status;
    }

    if (NULL != pSles->playerObject) {

        SLES_PRINTF("stopping player...");
        SLPlayItf playerPlay;
        SLresult result = (*(pSles->playerObject))->GetInterface(pSles->playerObject,
                SL_IID_PLAY, &playerPlay);

        ASSERT_EQ(SL_RESULT_SUCCESS, result);

        //stop player and recorder if they exist
        result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_STOPPED);
        ASSERT_EQ(SL_RESULT_SUCCESS, result);
    }

    if (NULL != pSles->recorderObject) {
        SLES_PRINTF("stopping recorder...");
        SLRecordItf recorderRecord;
        SLresult result = (*(pSles->recorderObject))->GetInterface(pSles->recorderObject,
                SL_IID_RECORD, &recorderRecord);
        ASSERT_EQ(SL_RESULT_SUCCESS, result);

        result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
        ASSERT_EQ(SL_RESULT_SUCCESS, result);
    }

    usleep(1000);

    audio_utils_fifo_deinit(&(pSles->fifo));
    delete[] pSles->fifoBuffer;

    SLES_PRINTF("slesDestroyServer 2");

    //        if (sndfile != NULL) {
    audio_utils_fifo_deinit(&(pSles->fifo2));
    delete[] pSles->fifo2Buffer;

    SLES_PRINTF("slesDestroyServer 3");

    //            sf_close(sndfile);
    //        }
    if (NULL != pSles->playerObject) {
        (*(pSles->playerObject))->Destroy(pSles->playerObject);
    }

    SLES_PRINTF("slesDestroyServer 4");

    if (NULL != pSles->recorderObject) {
        (*(pSles->recorderObject))->Destroy(pSles->recorderObject);
    }

    SLES_PRINTF("slesDestroyServer 5");

    (*(pSles->outputmixObject))->Destroy(pSles->outputmixObject);
    SLES_PRINTF("slesDestroyServer 6");
    (*(pSles->engineObject))->Destroy(pSles->engineObject);
    SLES_PRINTF("slesDestroyServer 7");

    //        free(pSles);
    //        pSles=NULL;

    status = SLES_SUCCESS;

    SLES_PRINTF("End slesDestroyServer: status = %d", status);
    return status;
}