Android audioEngine播放资源之外的音频有问题 (改了cocos引擎)

1.3.1版本
大致是:我用xhr从网络上下载MP3到jsb.的writeablepath下(unit8array),然后用cc.audioEngine来播放,发现:
有的可以播放,有的不行,怎么都不行。这个文件拿回到本地是好的,可以播放。把它放到资源中再用audioEngine是没问题的。
需求是从网络上播放一段音频,上次问android下是不行的,所以想先下载到本地再播放。
有别的思路吗?
logcat了一下(真心不是太熟),说


/libOpenSLES(9907): Sfplayer::setDataSource: invalid offset
/libOpenSLES(9907): no data locator for MediaPlayer object
/libOpenSLES(9907): Error (-23423232) encountered while perfetching
前面一些文件位置,大小什么的都对/UrlAudioPlayer

能播的,出现一大堆decode什么的
mp3.rar (124.1 KB)
内有两个MP3文件,一个能在/sdcard/下播,一个不能,但放回到资源中都可以播

又研究了一番,找了大概的问题:
(1)我把不能播放的MP3用格式工厂降低比特率,原来281K的减少到71K,可以播
(2)但大的MP3减少了还是有问题
(3)仿佛和文件大小有关
(4)看了错误的-2147483648,这是int的最大值,感觉可能是引擎的哪里以一个int值来计算什么,当文件过大时,超过int,会说offset有问题,
(5)urlaudioplayer cpp,其实C++不会
bool UrlAudioPlayer::prepare(const std::string &url, SLuint32 locatorType, std::shared_ptr assetFd, int start,
int length)
{
_url = url;
_assetFd = assetFd;

ALOGV("UrlAudioPlayer::prepare: %s, %d, %d, %d, %d", _url.c_str(), (int)locatorType, assetFd->getFd(), start,
     length);
SLDataSource audioSrc;

SLDataFormat_MIME formatMime = {SL_DATAFORMAT_MIME, nullptr, SL_CONTAINERTYPE_UNSPECIFIED};
audioSrc.pFormat = &formatMime;

//Note: locFd & locUri should be outside of the following if/else block
// Although locFd & locUri are only used inside if/else block, its lifecycle
// will be destroyed right after '}' block. And since we pass a pointer to
// 'audioSrc.pLocator=&locFd/&locUri', pLocator will point to an invalid address
// while invoking Engine::createAudioPlayer interface. So be care of change the position
// of these two variables.
SLDataLocator_AndroidFD locFd;

(6)再往上找,发现,previder中
Check audio file size to determine to use a PcmAudioService or UrlAudioPlayer,
也就是说小的当成是音效,用的pcmaudio ,这部分确可以播,logcat的结果也是这样,
大的用UrlAudioPlayer来播
(7)再往上
AudioPlayerProvider::AudioFileInfo AudioPlayerProvider::getFileInfo(
const std::string &audioFilePath)
{
AudioFileInfo info;
long fileSize = 0;
貌似 fileSize是long型的
而bool ret = urlPlayer->prepare(info.url, locatorType, info.assetFd, info.start, info.length);时
那边变成int了

大大们不喜勿喷
(7)改了之后还是不对,估计和locatorType有关,再看看
(8)改好了,是BUG,但最后的修改还是要引擎大大们再改,我用了一个临时的方案
在urlaudioplay.cpp中295行左右改成了这样
if (locatorType == SL_DATALOCATOR_ANDROIDFD)
{
locFd = {locatorType, _assetFd->getFd(), start, length};
audioSrc.pLocator = &locFd;
ALOGV(“locFd: locatorType: %d”, (int)locFd.locatorType);
if(_url[0]==’/’){
locUri = {SL_DATALOCATOR_URI, (SLchar *) _url.c_str()};
audioSrc.pLocator = &locUri;
ALOGV(“locUri: locatorType: %d”, (int)locUri.locatorType);
}
}
应该是provider中的472行
SLuint32 locatorType = info.assetFd > 0 ? SL_DATALOCATOR_ANDROIDFD : SL_DATALOCATOR_URI;

使发过来的 locatorType总是 SL_DATALOCATOR_ANDROIDFD而不是SL_DATALOCATOR_URI,我只好在里面再判断一次,但C++真是不会,那个makeshare什么的,不知道什么意思,只好改在这里了。
完了可以播了。
呼叫引擎大大们吧。
看到最新的引擎已经改了
SLuint32 locatorType = info.assetFd->getFd() > 0 ? SL_DATALOCATOR_ANDROIDFD : SL_DATALOCATOR_URI;

3赞

总结audioEngine的大致流程是这样的:
1.先在provider中判断音频大小,小的用PcmAudioService ,大的使用UrlAudioPlayer,大致用来区分音效和音乐。
// Check audio file size to determine to use a PcmAudioService or UrlAudioPlayer,
// generally PcmAudioService is used for playing short audio like game effects while
// playing background music uses UrlAudioPlayer
2.在UrlAudioPlayer中根据URL开头是不是有‘/‘来区分是资源asset还是一个物理文件再使用不同的locatorType.用的是Opensles来操作。
if (locatorType == SL_DATALOCATOR_ANDROIDFD)
{
locFd = {locatorType, _assetFd->getFd(), start, length};
audioSrc.pLocator = &locFd;
ALOGV(“locFd: locatorType: %d”, (int)locFd.locatorType);
if(_url[0]==’/’){
locUri = {SL_DATALOCATOR_URI, (SLchar *) _url.c_str()};
audioSrc.pLocator = &locUri;
ALOGV(“locUri: locatorType: %d”, (int)locUri.locatorType);
}
}
else if (locatorType == SL_DATALOCATOR_URI)
{
locUri = {locatorType, (SLchar *) _url.c_str()};
audioSrc.pLocator = &locUri;
ALOGV(“locUri: locatorType: %d”, (int)locUri.locatorType);
}

可以给个demo观摩观摩吗?

新版本已经改好了,我说的1.3.1是b版,对不起误导了