--- a/jdk/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCM.c Tue Apr 19 10:11:58 2011 +0400
+++ b/jdk/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCM.c Wed Apr 20 16:46:31 2011 +0400
@@ -239,6 +239,13 @@
snd_pcm_close(handle);
}
+/** Workaround for cr 7033899, 7030629:
+ * dmix plugin doesn't like flush (snd_pcm_drop) when the buffer is empty
+ * (just opened, underruned or already flushed).
+ * Sometimes it causes PCM falls to -EBADFD error,
+ * sometimes causes bufferSize change.
+ * To prevent unnecessary flushes AlsaPcmInfo::isRunning & isFlushed are used.
+ */
/* ******* ALSA PCM INFO ******************** */
typedef struct tag_AlsaPcmInfo {
snd_pcm_t* handle;
@@ -248,6 +255,8 @@
int frameSize; // storage size in Bytes
unsigned int periods;
snd_pcm_uframes_t periodSize;
+ short int isRunning; // see comment above
+ short int isFlushed; // see comment above
#ifdef GET_POSITION_METHOD2
// to be used exclusively by getBytePosition!
snd_pcm_status_t* positionStatus;
@@ -432,6 +441,9 @@
return NULL;
}
memset(info, 0, sizeof(AlsaPcmInfo));
+ // initial values are: stopped, flushed
+ info->isRunning = 0;
+ info->isFlushed = 1;
ret = openPCMfromDeviceID(deviceID, &(info->handle), isSource, FALSE /* do open device*/);
if (ret == 0) {
@@ -587,6 +599,14 @@
|| (state == SND_PCM_STATE_RUNNING)
|| (state == SND_PCM_STATE_XRUN)
|| (state == SND_PCM_STATE_SUSPENDED);
+ if (ret) {
+ info->isRunning = 1;
+ // source line should keep isFlushed value until Write() is called;
+ // for target data line reset it right now.
+ if (!isSource) {
+ info->isFlushed = 0;
+ }
+ }
TRACE1("< DAUDIO_Start %s\n", ret?"success":"error");
return ret?TRUE:FALSE;
}
@@ -606,6 +626,7 @@
ERROR1("ERROR in snd_pcm_pause: %s\n", snd_strerror(ret));
return FALSE;
}
+ info->isRunning = 0;
TRACE0("< DAUDIO_Stop success\n");
return TRUE;
}
@@ -651,8 +672,7 @@
return -1;
}
return 1;
- }
- else if (err == -ESTRPIPE) {
+ } else if (err == -ESTRPIPE) {
TRACE0("xrun_recovery: suspended.\n");
ret = snd_pcm_resume(info->handle);
if (ret < 0) {
@@ -667,11 +687,11 @@
return -1;
}
return 1;
- }
- else if (err == -EAGAIN) {
+ } else if (err == -EAGAIN) {
TRACE0("xrun_recovery: EAGAIN try again flag.\n");
return 0;
}
+
TRACE2("xrun_recovery: unexpected error %d: %s\n", err, snd_strerror(err));
return -1;
}
@@ -691,6 +711,7 @@
TRACE0("< DAUDIO_Write returning -1\n");
return -1;
}
+
count = 2; // maximum number of trials to recover from underrun
//frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize);
frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize);
@@ -712,6 +733,12 @@
}
} while (TRUE);
//ret = snd_pcm_frames_to_bytes(info->handle, writtenFrames);
+
+ if (writtenFrames > 0) {
+ // reset "flushed" flag
+ info->isFlushed = 0;
+ }
+
ret = (int) (writtenFrames * info->frameSize);
TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret);
return ret;
@@ -736,6 +763,11 @@
TRACE0("< DAUDIO_Read returning -1\n");
return -1;
}
+ if (!info->isRunning && info->isFlushed) {
+ // PCM has nothing to read
+ return 0;
+ }
+
count = 2; // maximum number of trials to recover from error
//frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize);
frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize);
@@ -784,12 +816,22 @@
int ret;
TRACE0("DAUDIO_Flush\n");
+
+ if (info->isFlushed) {
+ // nothing to drop
+ return 1;
+ }
+
ret = snd_pcm_drop(info->handle);
if (ret != 0) {
ERROR1("ERROR in snd_pcm_drop: %s\n", snd_strerror(ret));
return FALSE;
}
- ret = DAUDIO_Start(id, isSource);
+
+ info->isFlushed = 1;
+ if (info->isRunning) {
+ ret = DAUDIO_Start(id, isSource);
+ }
return ret;
}
@@ -800,7 +842,7 @@
int ret;
state = snd_pcm_state(info->handle);
- if (state == SND_PCM_STATE_XRUN) {
+ if (info->isFlushed || state == SND_PCM_STATE_XRUN) {
// if in xrun state then we have the entire buffer available,
// not 0 as alsa reports
ret = info->bufferSizeInBytes;
@@ -841,7 +883,7 @@
snd_pcm_state_t state;
state = snd_pcm_state(info->handle);
- if (state != SND_PCM_STATE_XRUN) {
+ if (!info->isFlushed && state != SND_PCM_STATE_XRUN) {
#ifdef GET_POSITION_METHOD2
snd_timestamp_t* ts;
snd_pcm_uframes_t framesAvail;