提问人:Nerdy Bunz 提问时间:5/17/2018 更新时间:6/2/2022 访问量:1547
Android AudioTrack.onPlaybackPositionUpdateListener 并不总是按时触发
Android AudioTrack.onPlaybackPositionUpdateListener not always firing on time
问:
我注意到 AudioTrack.setPlaybackPositionUpdateListener() 有时似乎无法按预期工作(至少在 API 19-22 的 Android Studio 模拟器中)。
我做了一个小测试程序,它有一个按钮,当按下它时,开始向 AudioTrack 提供一秒钟长的音频缓冲区。
AudioTrack 应该使用 onPeriodicNotification() 进行回调,这反过来又会翻转 Activity 的背景颜色并生成 Log。
预期行为:
按下开始按钮后,或多或少每秒发送和接收一次通知。
这确实在大多数时候发生,但有时(似乎主要在 API 19-22 上):
第一个(一秒钟后)通知被遗漏/推迟,取而代之的是,我们在两秒钟内同时收到两个通知。
为什么会这样?有没有更好的方法可以根据播放头位置获得回调?
我能想到的唯一原因可能是 CPU 频率缩放问题,如本视频的 19:30 左右所述。
主要活动:
public class MainActivity extends Activity {
View rootView;
Button startButton;
int initialBackgroundColor;
boolean colorFlipper = false;
boolean isPlaying = false;
// AUDIO -------------
AudioTrack audioTrack;
int sampleRateInHz = 44100;
int bufferSizeInBytes = 44100;
byte[] silenceArray;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rootView = findViewById(R.id.rootView);
startButton = findViewById(R.id.startButton);
initialBackgroundColor = rootView.getDrawingCacheBackgroundColor();
// AUDIO -------------
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRateInHz, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufferSizeInBytes, AudioTrack.MODE_STREAM);
audioTrack.setPositionNotificationPeriod(44100); // this amounts to one second
// create "dummy" (silent) sound... one second long
silenceArray = new byte[bufferSizeInBytes];
for (int i = 0; i < (bufferSizeInBytes-1); i++)
silenceArray[i] = 0;
}
public void startPressed(View v) {
boolean wasPlayingWhenPressed = startButton.isSelected();
startButton.setSelected(!startButton.isSelected());
if (wasPlayingWhenPressed) {
stop();
startButton.setText("START");
} else {
start();
startButton.setText("STOP");
}
}
private void start() {
isPlaying = true;
audioTrack.reloadStaticData();
audioTrack.play();
Runnable r = new Runnable() {
public void run() {
audioTrack.setPlaybackPositionUpdateListener(new AudioTrack.OnPlaybackPositionUpdateListener(){
@Override
public void onMarkerReached(AudioTrack arg0) {
}
@Override
public void onPeriodicNotification(AudioTrack arg0) {
// this *should* be called every second after play is pressed,
// but sometimes the first call is postponed and comes out
// simultaneously with the second call
Log.i("XXX","onPeriodicNotification() was called");
flipBackgroundColor();
}
});
while(isPlaying) {
audioTrack.write(silenceArray,0,silenceArray.length);
}
}
};
Thread backround_thread = new Thread(r);
backround_thread.start();
}
private void stop() {
isPlaying = false;
audioTrack.stop();
}
private void flipBackgroundColor(){
colorFlipper = !colorFlipper;
if (colorFlipper) {
rootView.setBackgroundColor(Color.RED);
} else {
rootView.setBackgroundColor(initialBackgroundColor);
}
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rootView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/startButton"
android:onClick="startPressed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="start"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
build.gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.example.boober.stackqaudiotrackcallback"
minSdkVersion 19
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
答: 暂无答案
上一个:套接字 IO 发出失败回调
评论