1

我正在尝试为我正在使用 NDK 和 100% 本机代码构建的音频采样器应用程序从 SD 卡中读取 wav 文件。我有一个方法,它遍历包含示例路径的预定义数组,并将每个路径单独流式传输到数据缓冲区中,以便稍后由 OpenSL 播放。

当我将文件作为资产加载时,使用以下方法:

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;
}

他们加载没有问题。但对于我的应用程序,我希望用户也能够从 SD 卡中读取样本。我将文件路径更改为 SD 卡上的硬编码位置(仅用于测试),并使用 fopen() 和 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);");
}

这给了我可怕的 ANR 和不可避免的崩溃:

06-06 11:42:30.915: I/dalvikvm(7222): threadid=3: 对信号 3 做出反应 06-06 11:42:30.915: A/libc(7222): 致命信号 11 (SIGSEGV) 在 0x0000000c (代码=1)

但奇怪的是,它的发生似乎相当随机——有 36 个奇数样本,有时错误出现在第 4 个之后,有时在 20 个左右之后出现。在阅读了这个线程之后,它似乎是一个分段错误,但我不知道它是如何引起的——或者这两种方法之间的区别是什么。

来自文件头 *fmttype 和 *databytes 的值每次都 100% 正确返回。

我对 C 很陌生,所以很可能我在做一些明显错误的事情——如果有经验的人能够阐明原因可能是什么,我将不胜感激。

更新:我使用 AAsset_read() 切换回来,仍然得到:

06-06 12:33:50.393: I/dalvikvm(9755): threadid=3: 对信号 3 做出反应 06-06 12:33:50.393: I/dalvikvm(9755): 将堆栈跟踪写入 '/data/anr/痕迹.txt'

但是文件每次仍然可以正常加载,并且应用程序不会崩溃。对于 512 MB 的测试平板电脑,我的测试样本的总大小为 48.4 MB - 这会导致问题吗?不过,如果是这样,我看不出使用 AAsset_read() 会有什么不同。

4

1 回答 1

1

您正在分配HEADER_SIZE字节:

(unsigned short*) malloc(HEADER_SIZE);

然后将HEADER_SIZE * 2字节读入其中,溢出缓冲区:

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

fread()乘以sizeof(unsigned short)HEADER_SIZE加倍。)

你对databytes. android 资产实现不会失败,因为您正在读取正确数量的数据。通过更改sizeof(unsigned short)为来修复它1

无关:如果 fopen() 返回 NULL,您可能应该从函数返回,而不是处理未初始化的数据。

“信号 3”消息仅表示系统正在向应用程序请求堆栈跟踪,可能是因为主线程很忙并且没有响应消息。

于 2013-06-06T02:03:56.313 回答