我一直试图在今天整天解决这个问题,在其他日子里花费太多时间。但今天我至少能够改善这个问题。
我有一个带有搞乱标题的.acc音频文件,让我们调用它"BadFile"
:根据我在前几天注意到的android本机C代码的logcat转储,标题说该文件有44.100Hz ,但数据本身有0Hz。
我有一个文件的arraylist,表示一个播放列表和一个int指针,用于定义在给定时刻播放的歌曲。当我在播放列表中排队一些歌曲时,可以说GoodFile1,GoodFile2,BadFile,GoodFile3,GoodFile4等...,指针设置为0,GoodFile1开始播放。
//这是从Thread.currentThread()。getId()== 1
调用的 private void play() {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
playCicle();
}
});
t.start();
}
private synchronized void playCicle() {
Log.e("THREAD" , "T:" + Thread.currentThread().getId());
Log.e("TRYING TO PLAY", playlist.get(playPointer).getFile().getAbsolutePath());
try {
if(progressSenderRunnable != null) {
progressSenderRunnable.stop();
}
if(myMP != null) {
myMP.release();
}
myMP = new MediaPlayer();
myMP.setAudioStreamType(AudioManager.STREAM_MUSIC);
myMP.setDataSource(mService, Uri.parse(Uri.encode(playlist.get(playPointer).getFile().getAbsolutePath())));
setOnPrepareListener();
myMP.prepare();
setOnCompletionListener();
setOnErrorListener();
myMP.start();
sendImPlaying();
} catch (IllegalArgumentException e) {
e.printStackTrace();
return;
} catch (SecurityException e) {
e.printStackTrace();
return;
} catch (IllegalStateException e) {
e.printStackTrace();
return;
} catch (IOException e) {
e.printStackTrace();
return;
}
Log.e("METHOD " , "EXITING");
}
private void setOnCompletionListener() {
myMP.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer arg0) {
Log.e("onCompletionthread" , "T: "+Thread.currentThread().getId());
Thread t = new Thread(new Runnable() {
@Override
public void run() {
if(!userSetPlayPointerNext && !userSetPlayPointerPrevious) {
playPointer++;
}
userSetPlayPointerNext = false;
userSetPlayPointerPrevious = false;
if(playPointer < playlist.size()) {
play();
}
else {
if(progressSenderRunnable != null) {
progressSenderRunnable.stop();
}
if(myMP != null) {
myMP.release();
}
sendImStopped();
}
}
});
t.start();
}
});
}
当它开始播放第一首歌时,我点击下一个按钮,导致ID为1的线程调用此下一个方法。
void playNextSong() {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
if(isPlaying() && playPointer < playlist.size() - 1) {
playPointer++;
userSetPlayPointerNext = true;
myMP.seekTo(myMP.getDuration() - 1);
}
}
});
t.start();
}
GoodFile2开始播放。 然后我开始垃圾邮件下一个按钮,UI就会挂起。在这个挂起后,我可以垃圾邮件下一个按钮就好了(因为我们已经过了BadFile)。
10-17 21:18:23.734: E/THREAD(24021): T:41
10-17 21:18:23.734: E/TRYING TO PLAY(24021): /mnt/sdcard/Music/BadFileTest/01_Compay Segundo - Te Apartes De Mi.mp3
10-17 21:18:23.744: E/METHOD(24021): EXITING
10-17 21:18:23.744: E/PREPARED(24021): PREPARED
10-17 21:18:24.364: E/Service rcv(24021): 17
10-17 21:18:24.364: E/back in handler(24021): 1
10-17 21:18:24.384: E/onCompletionthread(24021): T: 1
10-17 21:18:24.384: E/THREAD(24021): T:45
10-17 21:18:24.384: E/TRYING TO PLAY(24021): /mnt/sdcard/Music/BadFileTest/02 - Blue.aac
10-17 21:18:24.394: E/METHOD(24021): EXITING
10-17 21:18:24.724: E/PREPARED(24021): PREPARED
10-17 21:18:28.914: E/onCompletionthread(24021): T: 1
10-17 21:18:28.924: E/THREAD(24021): T:48
10-17 21:18:28.924: E/TRYING TO PLAY(24021): /mnt/sdcard/Music/BadFileTest/02_Ibrahím Ferrer - Ay Candela.mp3
10-17 21:18:28.944: E/METHOD(24021): EXITING
10-17 21:18:29.074: E/PREPARED(24021): PREPARED
At:10-17 21:18:23.734你可以看到GoodFile1几乎被ID为41的线程播放
At:10-17 21:18:24.364:您可以看到服务恢复playNextSong()
的op_code。
At:10-17 21:18:24.364 ::你可以看到从playNextSong()
同时,ID为45的线程正在加载BadFile并退出playNextSong()
方法。
现在这里是悬念:
10-17 21:18:24.724:E / PREPARED(24021):PREPARED
10-17 21:18:28.914:E / onCompletionthread(24021):T:1
在这4s期间,我的UI无法使用。我所看到的是,即使没有从主线程调用setOnCompletion侦听器,它也是在侦听器调用时调用的主线程,尽管我不确定这是否与挂起有关。
此刻我可能有太多不必要的线程,但我试图尽可能远离主线程完成大部分工作。我将来会改变它。
此时我认为synchronized关键字是无用的,因为我正在使用completionListener来启动新线程来播放下一首歌曲。
如果有人对我所犯的错误有所了解,那就是让我支付那些4s,我会更加乐观!
修改
我正在谈论的控制台转储,这个警告不会出现在我的软件包logcat过滤器中:
10-18 07:46:37.055: E/THREAD(10772): T:21
10-18 07:46:37.055: E/TRYING TO PLAY(10772): /mnt/sdcard/Music/BadFileTest/02 - Blue.aac
10-18 07:46:37.075: I/StagefrightPlayer(157): setDataSource('/mnt/sdcard/Music/BadFileTest/02 - Blue.aac')
10-18 07:46:37.625: V/OMXCodec(157): Attempting to allocate OMX node 'OMX.Nvidia.aac.decoder'
10-18 07:46:37.625: V/OMXCodec(157): Attempting to allocate OMX node 'OMX.TI.AAC.decode'
10-18 07:46:37.625: V/OMXCodec(157): Successfully allocated software codec 'AACDecoder'
10-18 07:46:37.625: E/PREPARED(10772): PREPARED
10-18 07:46:37.625: E/start(10772): before
10-18 07:46:37.625: W/AACDecoder(157): Sample rate was 44100 Hz, but now is 0 Hz
10-18 07:46:37.625: E/start(10772): after
10-18 07:46:37.635: W/AACDecoder(157): Disable AAC+/eAAC+ since upsampling factor is 1
10-18 07:46:37.635: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
10-18 07:46:37.635: W/AACDecoder(157): AAC decoder returned error 30, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 30, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 30, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 30, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 30, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 30, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 30, substituting silence
10-18 07:46:37.645: W/AACDecoder(157): AAC decoder returned error 20, substituting silence
奇怪的是,这个编解码器错误警告的时间大约是4s,只是主线程挂起的时间。
答案 0 :(得分:0)
问题不在于我的客户端代码,它是在尝试解码BadFile时占用CPU的AAC解码器。刚用CPU监视器确认了这一点。因此它不是我的主要线程,它是整个系统。