Bug 840833 - Use actual playback position to calculate free buffer space and change start-after-write logic in sydneyaudio Android backend. r=padenot
authorMatthew Gregan <kinetik@flim.org>
Fri, 15 Feb 2013 16:19:42 +1300
changeset 122006 17579083472fc8e51f97007b128751d4f8b34b3f
parent 122005 7c0ef5c0e554aeab48a4bc6891cbc9965732b9d5
child 122007 19857f43d44b08e879ef24f0a554a963f558eab3
push id24314
push userryanvm@gmail.com
push dateFri, 15 Feb 2013 14:39:46 +0000
treeherdermozilla-central@326c5e4868fe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs840833
milestone21.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 840833 - Use actual playback position to calculate free buffer space and change start-after-write logic in sydneyaudio Android backend. r=padenot
media/libsydneyaudio/src/sydney_audio_android.c
--- a/media/libsydneyaudio/src/sydney_audio_android.c
+++ b/media/libsydneyaudio/src/sydney_audio_android.c
@@ -70,18 +70,16 @@ struct sa_stream {
   jobject output_unit;
   jbyteArray output_buf;
   unsigned int output_buf_size;
 
   unsigned int rate;
   unsigned int channels;
   unsigned int isPaused;
 
-  int64_t lastStartTime;
-  int64_t timePlaying;
   int64_t amountWritten;
   unsigned int bufferSize;
 
   jclass at_class;
 };
 
 static struct AudioTrack at;
 extern JNIEnv * GetJNIForThread();
@@ -150,18 +148,16 @@ sa_stream_create_pcm(
 
   s->output_unit = NULL;
   s->output_buf  = NULL;
   s->output_buf_size = 0;
   s->rate        = rate;
   s->channels    = channels;
   s->isPaused    = 0;
 
-  s->lastStartTime = 0;
-  s->timePlaying = 0;
   s->amountWritten = 0;
 
   s->bufferSize = 0;
 
   *_s = s;
   return SA_SUCCESS;
 }
 
@@ -327,30 +323,23 @@ sa_stream_write(sa_stream_t *s, const vo
                                s->output_buf,
                                0,
                                towrite);
     if (r < 0) {
       ALOG("%p - Write failed %d", s, r);
       break;
     }
 
-    /* AudioTrack::write is blocking when the AudioTrack is playing.  When
-       it's not playing, it's a non-blocking call that will return a short
-       write when the buffer is full.  Use a short write to indicate a good
-       time to start the AudioTrack playing. */
-    if (r != towrite) {
-      ALOG("%p - Buffer full, starting playback", s);
-      sa_stream_resume(s);
-    }
 
     p += r;
     wrote += r;
-  } while (wrote < nbytes);
+    s->amountWritten += r;
 
-  s->amountWritten += nbytes;
+    sa_stream_resume(s);
+  } while (wrote < nbytes);
 
   (*jenv)->PopLocalFrame(jenv, NULL);
 
   return r < 0 ? SA_ERROR_INVALID : SA_SUCCESS;
 }
 
 
 /*
@@ -361,27 +350,33 @@ sa_stream_write(sa_stream_t *s, const vo
 
 int
 sa_stream_get_write_size(sa_stream_t *s, size_t *size) {
 
   if (s == NULL || s->output_unit == NULL) {
     return SA_ERROR_NO_INIT;
   }
 
-  /* No android API for this, so estimate based on how much we have played and
-   * how much we have written. */
-  *size = s->bufferSize - ((s->timePlaying * s->channels * s->rate * sizeof(int16_t) /
-                            MILLISECONDS_PER_SECOND) - s->amountWritten);
+
+  /* No way to query the available buffer space directly, so calculate it from
+     the amount we've written and the current playback position. */
+  JNIEnv *jenv = GetJNIForThread();
+  int32_t framePosition = (*jenv)->CallIntMethod(jenv, s->output_unit, at.getpos);
+
+  int64_t bytePos = framePosition * s->channels * sizeof(int16_t);
+
+  *size = s->bufferSize - (s->amountWritten - bytePos);
 
   /* Available buffer space can't exceed bufferSize. */
   if (*size > s->bufferSize) {
     *size = s->bufferSize;
   }
 
-  ALOG("%p - Write Size tp=%lld aw=%lld sz=%zu", s, s->timePlaying, s->amountWritten, *size);
+  ALOG("%p - Write Size aw=%lld bufsz=%u pos=%lld sz=%zu",
+       s, s->amountWritten, s->bufferSize, bytePos, *size);
   return SA_SUCCESS;
 }
 
 
 int
 sa_stream_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos) {
 
   if (s == NULL || s->output_unit == NULL) {
@@ -405,24 +400,17 @@ sa_stream_pause(sa_stream_t *s) {
   if (s == NULL || s->output_unit == NULL) {
     return SA_ERROR_NO_INIT;
   }
 
   JNIEnv *jenv = GetJNIForThread();
   s->isPaused = 1;
 
   /* Update stats */
-  if (s->lastStartTime != 0) {
-    /* if lastStartTime is not zero, so playback has started */
-    struct timespec current_time;
-    clock_gettime(CLOCK_REALTIME, &current_time);
-    int64_t ticker = current_time.tv_sec * 1000 + current_time.tv_nsec / 1000000;
-    s->timePlaying += ticker - s->lastStartTime;
-  }
-  ALOG("%p - Pause total time playing: %lld total written: %lld", s,  s->timePlaying, s->amountWritten);
+  ALOG("%p - pause", s);
 
   (*jenv)->CallVoidMethod(jenv, s->output_unit, at.pause);
   return SA_SUCCESS;
 }
 
 
 int
 sa_stream_resume(sa_stream_t *s) {
@@ -431,22 +419,16 @@ sa_stream_resume(sa_stream_t *s) {
     return SA_ERROR_NO_INIT;
   }
 
   ALOG("%p - resume", s);
 
   JNIEnv *jenv = GetJNIForThread();
   s->isPaused = 0;
 
-  /* Update stats */
-  struct timespec current_time;
-  clock_gettime(CLOCK_REALTIME, &current_time);
-  int64_t ticker = current_time.tv_sec * 1000 + current_time.tv_nsec / 1000000;
-  s->lastStartTime = ticker;
-
   (*jenv)->CallVoidMethod(jenv, s->output_unit, at.play);
   return SA_SUCCESS;
 }
 
 
 int
 sa_stream_drain(sa_stream_t *s)
 {