changeset 4261:ea0aed4b75cd

7030629: closed/sun/audio/AudioClipClose/AudioClipClose.java test fails just against jdk7 b134 7033899: SoundTestSuite: test050 fails on Ubuntu Linux Reviewed-by: bae
author amenkov
date Wed, 20 Apr 2011 16:46:31 +0400
parents 4719cf8f5ae5
children 6c94f33c36d5
files src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCM.c
diffstat 1 files changed, 49 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCM.c	Tue Apr 19 10:11:58 2011 +0400
+++ b/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;