I'm trying to read wav files off the SD card for a audio sampler app I'm building using the NDK and 100% native code. I have a method which iterates through a predefined array containing the sample paths and streams each individually into a data buffer to be later played by OpenSL.

When I loaded the files as assets, using the following method:

int open_asset(AAssetManager* mgr, char* filename, int samp)
{

    assert(NULL != mgr);
    AAsset *asset = AAssetManager_open(mgr, filename, AASSET_MODE_BUFFER);

    __android_log_write(ANDROID_LOG_DEBUG, "ASSET", "AAssetManager_open");

    if (NULL == asset)
    {
        __android_log_write(ANDROID_LOG_DEBUG, "ASSET", "Asset not found, loading aborted.");
        return JNI_FALSE;
    }

    oneshot_samples[samp].buffer_header = (unsigned short*) malloc(HEADER_SIZE);
    AAsset_read(asset, oneshot_samples[samp].buffer_header, HEADER_SIZE);

    unsigned short* fmttype;
    unsigned long* databytes;

    fmttype = (oneshot_samples[samp].buffer_header + 10);

    if (*fmttype != 0x1)
    {
        __android_log_write(ANDROID_LOG_DEBUG, "ASSET", "*fmttype not PCM, loading aborted.");
        return JNI_FALSE;
    }

    databytes = (oneshot_samples[samp].buffer_header + 20);

    oneshot_samples[samp].data_size = *databytes;

    oneshot_samples[samp].buffer_data = (unsigned short*) malloc(*databytes);
    AAsset_seek(asset, HEADER_SIZE, SEEK_SET);
    AAsset_read(asset, oneshot_samples[samp].buffer_data, oneshot_samples[samp].data_size);

    __android_log_print(ANDROID_LOG_DEBUG, "ASSET", "*fmttype: %x", *fmttype);
    __android_log_print(ANDROID_LOG_DEBUG, "ASSET", "*databytes: %x", *databytes);

    AAsset_close(asset);

    __android_log_write(ANDROID_LOG_DEBUG, "ASSET", "AAsset_close(asset)");

    return JNI_TRUE;
}

They load without a problem. But for my app, I want the user to be able to read samples from the SD Card too. I changed the file paths to a hard coded location on the SD Card (just for testing), and tried the following method using fopen() and fread():

void open_external_file(char* filepath, int samp)
{

    FILE* fp;
    oneshot_samples[samp].buffer_header = (unsigned short*) malloc(HEADER_SIZE);

    __android_log_print(ANDROID_LOG_DEBUG, "open_external_file",
                        "filepath: %s", filepath);

    __android_log_print(ANDROID_LOG_DEBUG, "open_external_file",
                        "size of filepath: %d", sizeof filepath);

    if ((fp = fopen(filepath, "r")) != NULL)
    {
        __android_log_write(ANDROID_LOG_DEBUG, "open_external_file", "fopen()");

        fread(oneshot_samples[samp].buffer_header, sizeof(unsigned short), HEADER_SIZE, fp);
    }

    unsigned short* fmttype;
    unsigned long* databytes;

    fmttype = (oneshot_samples[samp].buffer_header + 10);

    if (*fmttype != 0x1)
    {
        __android_log_write(ANDROID_LOG_DEBUG, "open_external_file", "*fmttype not PCM, loading aborted.");
    }

    databytes = (oneshot_samples[samp].buffer_header + 20);
    oneshot_samples[samp].data_size = *databytes;
    oneshot_samples[samp].buffer_data = (unsigned short*) malloc(*databytes);

    __android_log_print(ANDROID_LOG_DEBUG, "open_external_file", "*fmttype: %x", *fmttype);
    __android_log_print(ANDROID_LOG_DEBUG, "open_external_file", "*databytes: %x", *databytes);


    fseek(fp , HEADER_SIZE , SEEK_SET);
    fread(oneshot_samples[samp].buffer_data, sizeof(unsigned short), oneshot_samples[samp].data_size, fp);

    fclose(fp);
    __android_log_write(ANDROID_LOG_DEBUG, "open_external_file", "fclose(fp);");
}

Which gives me the dreaded ANR and inevitable crash:

06-06 11:42:30.915: I/dalvikvm(7222): threadid=3: reacting to signal 3 06-06 11:42:30.915: A/libc(7222): Fatal signal 11 (SIGSEGV) at 0x0000000c (code=1)

But the weird thing is that it happens seemingly quite randomly - there are 36 odd samples, and sometimes the error appears after just the 4th, and sometimes after 20 or so. After reading this thread, it appears it could be a segmentation fault, but I'm at a loss as to how it could be caused - or what the difference between the two methods is.

The values from the file header *fmttype and *databytes are returned 100% correctly every time.

I'm very new to C so it's quite possible I'm doing something obviously wrong - would really appreciate if someone more experienced could shed some light onto what the cause may be.

Update: I switched back using AAsset_read(), and am still getting:

06-06 12:33:50.393: I/dalvikvm(9755): threadid=3: reacting to signal 3 06-06 12:33:50.393: I/dalvikvm(9755): Wrote stack traces to '/data/anr/traces.txt'

But the files still load fine every time, and the app does not crash. The total size of my test samples is 48.4 MB for a 512 MB test tablet - could this be causing the issue? Still, if it was I don't see how using AAsset_read() would make a difference.

有帮助吗?

解决方案

You're allocating HEADER_SIZE bytes:

(unsigned short*) malloc(HEADER_SIZE);

and then reading HEADER_SIZE * 2 bytes into it, overflowing the buffer:

fread(oneshot_samples[samp].buffer_header, sizeof(unsigned short), HEADER_SIZE, fp);

(fread() multiplies sizeof(unsigned short) by HEADER_SIZE, doubling it.)

You do the same over-read again for databytes. It doesn't fail for the android asset implementation because you're reading the correct amount of data in. Fix it by changing sizeof(unsigned short) to 1.

Unrelated: if fopen() returns NULL, you should probably return from the function, rather than processing uninitialized data.

The "signal 3" message just means the system is requesting a stack trace from the app, possibly because the main thread was busy and didn't respond to a message.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top