summaryrefslogtreecommitdiffstats
path: root/variablespeed/jni/variablespeed.cc
blob: 4bdbbcc9071499accc662facfe7a7938be3bf41f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <variablespeed.h>

#include <unistd.h>
#include <stdlib.h>

#include <sola_time_scaler.h>
#include <ring_buffer.h>

#include <hlogging.h>

#include <vector>

#include <sys/system_properties.h>

// ****************************************************************************
// Constants, utility methods, structures and other miscellany used throughout
// this file.

namespace {

// These variables are used to determine the size of the buffer queue used by
// the decoder.
// This is not the same as the large buffer used to hold the uncompressed data
// - for that see the member variable decodeBuffer_.
// The choice of 1152 corresponds to the number of samples per mp3 frame, so is
// a good choice of size for a decoding buffer in the absence of other
// information (we don't know exactly what formats we will be working with).
const size_t kNumberOfBuffersInQueue = 4;
const size_t kNumberOfSamplesPerBuffer = 1152;
const size_t kBufferSizeInBytes = 2 * kNumberOfSamplesPerBuffer;
const size_t kSampleSizeInBytes = 4;

// When calculating play buffer size before pushing to audio player.
const size_t kNumberOfBytesPerInt16 = 2;

// How long to sleep during the main play loop and the decoding callback loop.
// In due course this should be replaced with the better signal and wait on
// condition rather than busy-looping.
const int kSleepTimeMicros = 1000;

// Used in detecting errors with the OpenSL ES framework.
const SLuint32 kPrefetchErrorCandidate =
    SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE;

// Structure used when we perform a decoding callback.
typedef struct CallbackContext_ {
  // Pointer to local storage buffers for decoded audio data.
  int8_t* pDataBase;
  // Pointer to the current buffer within local storage.
  int8_t* pData;
  // Used to read the sample rate and channels from the decoding stream during
  // the first decoding callback.
  SLMetadataExtractionItf decoderMetadata;
  // The play interface used for reading duration.
  SLPlayItf playItf;
} CallbackContext;

// Local storage for decoded audio data.
int8_t pcmData[kNumberOfBuffersInQueue * kBufferSizeInBytes];

#define CheckSLResult(message, result) \
    CheckSLResult_Real(message, result, __LINE__)

// Helper function for debugging - checks the OpenSL result for success.
void CheckSLResult_Real(const char* message, SLresult result, int line) {
  // This can be helpful when debugging.
  // LOGD("sl result %d for %s", result, message);
  if (SL_RESULT_SUCCESS != result) {
    LOGE("slresult was %d at %s file variablespeed line %d",
        static_cast<int>(result), message, line);
  }
  CHECK(SL_RESULT_SUCCESS == result);
}

// Whether logging should be enabled. Only used if LOG_OPENSL_API_CALL is
// defined to use it.
bool gLogEnabled = false;
// The property to set in order to enable logging.
const char *const kLogTagVariableSpeed = "log.tag.VariableSpeed";

bool ShouldLog() {
  char buffer[PROP_VALUE_MAX];
  __system_property_get(kLogTagVariableSpeed, buffer);
  return strlen(buffer) > 0;
}

}  // namespace

// ****************************************************************************
// Static instance of audio engine, and methods for getting, setting and
// deleting it.

// The single global audio engine instance.
AudioEngine* AudioEngine::audioEngine_ = NULL;
android::Mutex publishEngineLock_;

AudioEngine* AudioEngine::GetEngine() {
  android::Mutex::Autolock autoLock(publishEngineLock_);
  if (audioEngine_ == NULL) {
    LOGE("you haven't initialized the audio engine");
    CHECK(false);
    return NULL;
  }
  return audioEngine_;
}

void AudioEngine::SetEngine(AudioEngine* engine) {
  if (audioEngine_ != NULL) {
    LOGE("you have already set the audio engine");
    CHECK(false);
    return;
  }
  audioEngine_ = engine;
}

bool AudioEngine::CompareAndSetEngine(AudioEngine* expect, AudioEngine* update) {
  android::Mutex::Autolock autoLock(publishEngineLock_);
  if (audioEngine_ == expect) {
    DeleteEngine();
    audioEngine_ = update;
    return true;
  }
  return false;
}

void AudioEngine::DeleteEngine() {
  if (audioEngine_ != NULL) {
    delete audioEngine_;
    audioEngine_ = NULL;
  }
}

// ****************************************************************************
// The callbacks from the engine require static callback functions.
// Here are the static functions - they just delegate to instance methods on
// the engine.

static void PlayingBufferQueueCb(SLAndroidSimpleBufferQueueItf, void*) {
  AudioEngine::GetEngine()->PlayingBufferQueueCallback();
}

static void PrefetchEventCb(SLPrefetchStatusItf caller, void*, SLuint32 event) {
  AudioEngine::GetEngine()->PrefetchEventCallback(caller, event);
}

static void DecodingBufferQueueCb(SLAndroidSimpleBufferQueueItf queueItf,
    void *context) {
  AudioEngine::GetEngine()->DecodingBufferQueueCallback(queueItf, context);
}

static void DecodingEventCb(SLPlayItf caller, void*, SLuint32 event) {
  AudioEngine::GetEngine()->DecodingEventCallback(caller, event);
}

// ****************************************************************************
// Macros for making working with OpenSL easier.

// Log based on the value of a property.
#define LOG_OPENSL_API_CALL(string) (gLogEnabled && LOGV(string))

// The regular macro: log an api call, make the api call, check the result.
#define OpenSL(obj, method, ...) \
{ \
  LOG_OPENSL_API_CALL("OpenSL " #method "(" #obj ", " #__VA_ARGS__ ")"); \
  SLresult result = (*obj)->method(obj, __VA_ARGS__); \
  CheckSLResult("OpenSL " #method "(" #obj ", " #__VA_ARGS__ ")", result); \
}

// Special case call for api call that has void return value, can't be checked.
#define VoidOpenSL(obj, method) \
{ \
  LOG_OPENSL_API_CALL("OpenSL (void) " #method "(" #obj ")"); \
  (*obj)->method(obj); \
}

// Special case for api call with checked result but takes no arguments.
#define OpenSL0(obj, method) \
{ \
  LOG_OPENSL_API_CALL("OpenSL " #method "(" #obj ")"); \
  SLresult result = (*obj)->method(obj); \
  CheckSLResult("OpenSL " #method "(" #obj ")", result); \
}

// Special case for api call whose result we want to store, not check.
// We have to encapsulate the two calls in braces, so that this expression
// evaluates to the last expression not the first.
#define ReturnOpenSL(obj, method, ...) \
( \
    LOG_OPENSL_API_CALL("OpenSL (int) " \
        #method "(" #obj ", " #__VA_ARGS__ ")"), \
    (*obj)->method(obj, __VA_ARGS__) \
) \

// ****************************************************************************
// Static utility methods.

// Set the audio stream type for the player.
//
// Must be called before it is realized.
//
// The caller must have requested the SL_IID_ANDROIDCONFIGURATION interface when
// creating the player.
static void setAudioStreamType(SLObjectItf audioPlayer, SLint32 audioStreamType) {
  SLAndroidConfigurationItf playerConfig;
  OpenSL(audioPlayer, GetInterface, SL_IID_ANDROIDCONFIGURATION, &playerConfig);
  // The STREAM_XXX constants defined by android.media.AudioManager match the
  // corresponding SL_ANDROID_STREAM_XXX constants defined by
  // include/SLES/OpenSLES_AndroidConfiguration.h, so we can just pass the
  // value across.
  OpenSL(playerConfig, SetConfiguration, SL_ANDROID_KEY_STREAM_TYPE,
         &audioStreamType, sizeof(audioStreamType));
}

// Must be called with callbackLock_ held.
static void ReadSampleRateAndChannelCount(CallbackContext *pContext,
    SLuint32 *sampleRateOut, SLuint32 *channelsOut) {
  SLMetadataExtractionItf decoderMetadata = pContext->decoderMetadata;
  SLuint32 itemCount;
  OpenSL(decoderMetadata, GetItemCount, &itemCount);
  SLuint32 i, keySize, valueSize;
  SLMetadataInfo *keyInfo, *value;
  for (i = 0; i < itemCount; ++i) {
    keyInfo = value = NULL;
    keySize = valueSize = 0;
    OpenSL(decoderMetadata, GetKeySize, i, &keySize);
    keyInfo = static_cast<SLMetadataInfo*>(malloc(keySize));
    if (keyInfo) {
      OpenSL(decoderMetadata, GetKey, i, keySize, keyInfo);
      if (keyInfo->encoding == SL_CHARACTERENCODING_ASCII
          || keyInfo->encoding == SL_CHARACTERENCODING_UTF8) {
        OpenSL(decoderMetadata, GetValueSize, i, &valueSize);
        value = static_cast<SLMetadataInfo*>(malloc(valueSize));
        if (value) {
          OpenSL(decoderMetadata, GetValue, i, valueSize, value);
          if (strcmp((char*) keyInfo->data, ANDROID_KEY_PCMFORMAT_SAMPLERATE) == 0) {
            SLuint32 sampleRate = *(reinterpret_cast<SLuint32*>(value->data));
            LOGD("sample Rate: %d", sampleRate);
            *sampleRateOut = sampleRate;
          } else if (strcmp((char*) keyInfo->data, ANDROID_KEY_PCMFORMAT_NUMCHANNELS) == 0) {
            SLuint32 channels = *(reinterpret_cast<SLuint32*>(value->data));
            LOGD("channels: %d", channels);
            *channelsOut = channels;
          }
          free(value);
        }
      }
      free(keyInfo);
    }
  }
}

// Must be called with callbackLock_ held.
static void RegisterCallbackContextAndAddEnqueueBuffersToDecoder(
    SLAndroidSimpleBufferQueueItf decoderQueue, CallbackContext* context) {
  // Register a callback on the decoder queue, so that we will be called
  // throughout the decoding process (and can then extract the decoded audio
  // for the next bit of the pipeline).
  OpenSL(decoderQueue, RegisterCallback, DecodingBufferQueueCb, context);

  // Enqueue buffers to map the region of memory allocated to store the
  // decoded data.
  for (size_t i = 0; i < kNumberOfBuffersInQueue; i++) {
    OpenSL(decoderQueue, Enqueue, context->pData, kBufferSizeInBytes);
    context->pData += kBufferSizeInBytes;
  }
  context->pData = context->pDataBase;
}

// ****************************************************************************
// Constructor and Destructor.

AudioEngine::AudioEngine(size_t targetFrames, float windowDuration,
    float windowOverlapDuration, size_t maxPlayBufferCount, float initialRate,
    size_t decodeInitialSize, size_t decodeMaxSize, size_t startPositionMillis,
    int audioStreamType)
    : decodeBuffer_(decodeInitialSize, decodeMaxSize),
      playingBuffers_(), freeBuffers_(), timeScaler_(NULL),
      floatBuffer_(NULL), injectBuffer_(NULL),
      mSampleRate(0), mChannels(0),
      targetFrames_(targetFrames),
      windowDuration_(windowDuration),
      windowOverlapDuration_(windowOverlapDuration),
      maxPlayBufferCount_(maxPlayBufferCount), initialRate_(initialRate),
      startPositionMillis_(startPositionMillis),
      audioStreamType_(audioStreamType),
      totalDurationMs_(0), decoderCurrentPosition_(0), startRequested_(false),
      stopRequested_(false), finishedDecoding_(false) {
  // Determine whether we should log calls.
  gLogEnabled = ShouldLog();
}

AudioEngine::~AudioEngine() {
  // destroy the time scaler
  if (timeScaler_ != NULL) {
    delete timeScaler_;
    timeScaler_ = NULL;
  }

  // delete all outstanding playing and free buffers
  android::Mutex::Autolock autoLock(playBufferLock_);
  while (playingBuffers_.size() > 0) {
    delete[] playingBuffers_.front();
    playingBuffers_.pop();
  }
  while (freeBuffers_.size() > 0) {
    delete[] freeBuffers_.top();
    freeBuffers_.pop();
  }

  delete[] floatBuffer_;
  floatBuffer_ = NULL;
  delete[] injectBuffer_;
  injectBuffer_ = NULL;
}

// ****************************************************************************
// Regular AudioEngine class methods.

void AudioEngine::SetVariableSpeed(float speed) {
  // TODO: Mutex for shared time scaler accesses.
  if (HasSampleRateAndChannels()) {
    GetTimeScaler()->set_speed(speed);
  } else {
    // This is being called at a point where we have not yet processed enough
    // data to determine the sample rate and number of channels.
    // Ignore the call.  See http://b/5140693.
    LOGD("set varaible speed called, sample rate and channels not ready yet");
  }
}

void AudioEngine::RequestStart() {
  android::Mutex::Autolock autoLock(lock_);
  startRequested_ = true;
}

void AudioEngine::ClearRequestStart() {
  android::Mutex::Autolock autoLock(lock_);
  startRequested_ = false;
}

bool AudioEngine::GetWasStartRequested() {
  android::Mutex::Autolock autoLock(lock_);
  return startRequested_;
}

void AudioEngine::RequestStop() {
  android::Mutex::Autolock autoLock(lock_);
  stopRequested_ = true;
}

int AudioEngine::GetCurrentPosition() {
  android::Mutex::Autolock autoLock(decodeBufferLock_);
  double result = decodeBuffer_.GetTotalAdvancedCount();
  // TODO: This is horrible, but should be removed soon once the outstanding
  // issue with get current position on decoder is fixed.
  android::Mutex::Autolock autoLock2(callbackLock_);
  return static_cast<int>(
      (result * 1000) / mSampleRate / mChannels + startPositionMillis_);
}

int AudioEngine::GetTotalDuration() {
  android::Mutex::Autolock autoLock(lock_);
  return static_cast<int>(totalDurationMs_);
}

video_editing::SolaTimeScaler* AudioEngine::GetTimeScaler() {
  if (timeScaler_ == NULL) {
    CHECK(HasSampleRateAndChannels());
    android::Mutex::Autolock autoLock(callbackLock_);
    timeScaler_ = new video_editing::SolaTimeScaler();
    timeScaler_->Init(mSampleRate, mChannels, initialRate_, windowDuration_,
        windowOverlapDuration_);
  }
  return timeScaler_;
}

bool AudioEngine::EnqueueNextBufferOfAudio(
    SLAndroidSimpleBufferQueueItf audioPlayerQueue) {
  size_t channels;
  {
    android::Mutex::Autolock autoLock(callbackLock_);
    channels = mChannels;
  }
  size_t frameSizeInBytes = kSampleSizeInBytes * channels;
  size_t frameCount = 0;
  while (frameCount < targetFrames_) {
    size_t framesLeft = targetFrames_ - frameCount;
    // If there is data already in the time scaler, retrieve it.
    if (GetTimeScaler()->available() > 0) {
      size_t retrieveCount = min(GetTimeScaler()->available(), framesLeft);
      int count = GetTimeScaler()->RetrieveSamples(
          floatBuffer_ + frameCount * channels, retrieveCount);
      if (count <= 0) {
        LOGD("error: count was %d", count);
        break;
      }
      frameCount += count;
      continue;
    }
    // If there is no data in the time scaler, then feed some into it.
    android::Mutex::Autolock autoLock(decodeBufferLock_);
    size_t framesInDecodeBuffer =
        decodeBuffer_.GetSizeInBytes() / frameSizeInBytes;
    size_t framesScalerCanHandle = GetTimeScaler()->input_limit();
    size_t framesToInject = min(framesInDecodeBuffer,
        min(targetFrames_, framesScalerCanHandle));
    if (framesToInject <= 0) {
      // No more frames left to inject.
      break;
    }
    for (size_t i = 0; i < framesToInject * channels; ++i) {
      injectBuffer_[i] = decodeBuffer_.GetAtIndex(i);
    }
    int count = GetTimeScaler()->InjectSamples(injectBuffer_, framesToInject);
    if (count <= 0) {
      LOGD("error: count was %d", count);
      break;
    }
    decodeBuffer_.AdvanceHeadPointerShorts(count * channels);
  }
  if (frameCount <= 0) {
    // We must have finished playback.
    if (GetEndOfDecoderReached()) {
      // If we've finished decoding, clear the buffer - so we will terminate.
      ClearDecodeBuffer();
    }
    return false;
  }

  // Get a free playing buffer.
  int16* playBuffer;
  {
    android::Mutex::Autolock autoLock(playBufferLock_);
    if (freeBuffers_.size() > 0) {
      // If we have a free buffer, recycle it.
      playBuffer = freeBuffers_.top();
      freeBuffers_.pop();
    } else {
      // Otherwise allocate a new one.
      playBuffer = new int16[targetFrames_ * channels];
    }
  }

  // Try to play the buffer.
  for (size_t i = 0; i < frameCount * channels; ++i) {
    playBuffer[i] = floatBuffer_[i];
  }
  size_t sizeOfPlayBufferInBytes =
      frameCount * channels * kNumberOfBytesPerInt16;
  SLresult result = ReturnOpenSL(audioPlayerQueue, Enqueue, playBuffer,
      sizeOfPlayBufferInBytes);
  if (result == SL_RESULT_SUCCESS) {
    android::Mutex::Autolock autoLock(playBufferLock_);
    playingBuffers_.push(playBuffer);
  } else {
    LOGE("could not enqueue audio buffer");
    delete[] playBuffer;
  }

  return (result == SL_RESULT_SUCCESS);
}

bool AudioEngine::GetEndOfDecoderReached() {
  android::Mutex::Autolock autoLock(lock_);
  return finishedDecoding_;
}

void AudioEngine::SetEndOfDecoderReached() {
  android::Mutex::Autolock autoLock(lock_);
  finishedDecoding_ = true;
}

bool AudioEngine::PlayFileDescriptor(int fd, int64 offset, int64 length) {
  SLDataLocator_AndroidFD loc_fd = {
      SL_DATALOCATOR_ANDROIDFD, fd, offset, length };
  SLDataFormat_MIME format_mime = {
      SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED };
  SLDataSource audioSrc = { &loc_fd, &format_mime };
  return PlayFromThisSource(audioSrc);
}

bool AudioEngine::PlayUri(const char* uri) {
  // Source of audio data for the decoding
  SLDataLocator_URI decUri = { SL_DATALOCATOR_URI,
      const_cast<SLchar*>(reinterpret_cast<const SLchar*>(uri)) };
  SLDataFormat_MIME decMime = {
      SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED };
  SLDataSource decSource = { &decUri, &decMime };
  return PlayFromThisSource(decSource);
}

bool AudioEngine::IsDecodeBufferEmpty() {
  android::Mutex::Autolock autoLock(decodeBufferLock_);
  return decodeBuffer_.GetSizeInBytes() <= 0;
}

void AudioEngine::ClearDecodeBuffer() {
  android::Mutex::Autolock autoLock(decodeBufferLock_);
  decodeBuffer_.Clear();
}

static size_t ReadDuration(SLPlayItf playItf) {
  SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
  OpenSL(playItf, GetDuration, &durationInMsec);
  if (durationInMsec == SL_TIME_UNKNOWN) {
    LOGE("can't get duration");
    return 0;
  }
  LOGD("duration: %d", static_cast<int>(durationInMsec));
  return durationInMsec;
}

static size_t ReadPosition(SLPlayItf playItf) {
  SLmillisecond positionInMsec = SL_TIME_UNKNOWN;
  OpenSL(playItf, GetPosition, &positionInMsec);
  if (positionInMsec == SL_TIME_UNKNOWN) {
    LOGE("can't get position");
    return 0;
  }
  LOGW("decoder position: %d", static_cast<int>(positionInMsec));
  return positionInMsec;
}

static void CreateAndRealizeEngine(SLObjectItf &engine,
    SLEngineItf &engineInterface) {
  SLEngineOption EngineOption[] = { {
      SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE } };
  SLresult result = slCreateEngine(&engine, 1, EngineOption, 0, NULL, NULL);
  CheckSLResult("create engine", result);
  OpenSL(engine, Realize, SL_BOOLEAN_FALSE);
  OpenSL(engine, GetInterface, SL_IID_ENGINE, &engineInterface);
}

SLuint32 AudioEngine::GetSLSampleRate() {
  android::Mutex::Autolock autoLock(callbackLock_);
  return mSampleRate * 1000;
}

SLuint32 AudioEngine::GetSLChannels() {
  android::Mutex::Autolock autoLock(callbackLock_);
  switch (mChannels) {
    case 2:
      return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
    case 1:
      return SL_SPEAKER_FRONT_CENTER;
    default:
      LOGE("unknown channels %d, using 2", mChannels);
      return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
  }
}

SLuint32 AudioEngine::GetChannelCount() {
  android::Mutex::Autolock autoLock(callbackLock_);
  return mChannels;
}

static void CreateAndRealizeAudioPlayer(SLuint32 slSampleRate,
    size_t channelCount, SLuint32 slChannels, SLint32 audioStreamType, SLObjectItf &outputMix,
    SLObjectItf &audioPlayer, SLEngineItf &engineInterface) {
  // Define the source and sink for the audio player: comes from a buffer queue
  // and goes to the output mix.
  SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
      SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2 };
  SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, channelCount, slSampleRate,
      SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
      slChannels, SL_BYTEORDER_LITTLEENDIAN};
  SLDataSource playingSrc = {&loc_bufq, &format_pcm};
  SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMix};
  SLDataSink audioSnk = {&loc_outmix, NULL};

  // Create the audio player, which will play from the buffer queue and send to
  // the output mix.
  const size_t playerInterfaceCount = 2;
  const SLInterfaceID iids[playerInterfaceCount] = {
      SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION };
  const SLboolean reqs[playerInterfaceCount] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
  OpenSL(engineInterface, CreateAudioPlayer, &audioPlayer, &playingSrc,
      &audioSnk, playerInterfaceCount, iids, reqs);
  setAudioStreamType(audioPlayer, audioStreamType);
  OpenSL(audioPlayer, Realize, SL_BOOLEAN_FALSE);
}

bool AudioEngine::HasSampleRateAndChannels() {
  android::Mutex::Autolock autoLock(callbackLock_);
  return mChannels != 0 && mSampleRate != 0;
}

bool AudioEngine::PlayFromThisSource(const SLDataSource& audioSrc) {
  ClearDecodeBuffer();

  SLObjectItf engine;
  SLEngineItf engineInterface;
  CreateAndRealizeEngine(engine, engineInterface);

  // Define the source and sink for the decoding player: comes from the source
  // this method was called with, is sent to another buffer queue.
  SLDataLocator_AndroidSimpleBufferQueue decBuffQueue;
  decBuffQueue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
  decBuffQueue.numBuffers = kNumberOfBuffersInQueue;
  // A valid value seems required here but is currently ignored.
  SLDataFormat_PCM pcm = {SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_44_1,
      SL_PCMSAMPLEFORMAT_FIXED_16, 16,
      SL_SPEAKER_FRONT_LEFT, SL_BYTEORDER_LITTLEENDIAN};
  SLDataSink decDest = { &decBuffQueue, &pcm };

  // Create the decoder with the given source and sink.
  const size_t decoderInterfaceCount = 5;
  SLObjectItf decoder;
  const SLInterfaceID decodePlayerInterfaces[decoderInterfaceCount] = {
      SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_PREFETCHSTATUS, SL_IID_SEEK,
      SL_IID_METADATAEXTRACTION, SL_IID_ANDROIDCONFIGURATION };
  const SLboolean decodePlayerRequired[decoderInterfaceCount] = {
      SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
  SLDataSource sourceCopy(audioSrc);
  OpenSL(engineInterface, CreateAudioPlayer, &decoder, &sourceCopy, &decDest,
      decoderInterfaceCount, decodePlayerInterfaces, decodePlayerRequired);
  // Not sure if this is necessary, but just in case.
  setAudioStreamType(decoder, audioStreamType_);
  OpenSL(decoder, Realize, SL_BOOLEAN_FALSE);

  // Get the play interface from the decoder, and register event callbacks.
  // Get the buffer queue, prefetch and seek interfaces.
  SLPlayItf decoderPlay = NULL;
  SLAndroidSimpleBufferQueueItf decoderQueue = NULL;
  SLPrefetchStatusItf decoderPrefetch = NULL;
  SLSeekItf decoderSeek = NULL;
  SLMetadataExtractionItf decoderMetadata = NULL;
  OpenSL(decoder, GetInterface, SL_IID_PLAY, &decoderPlay);
  OpenSL(decoderPlay, SetCallbackEventsMask, SL_PLAYEVENT_HEADATEND);
  OpenSL(decoderPlay, RegisterCallback, DecodingEventCb, NULL);
  OpenSL(decoder, GetInterface, SL_IID_PREFETCHSTATUS, &decoderPrefetch);
  OpenSL(decoder, GetInterface, SL_IID_SEEK, &decoderSeek);
  OpenSL(decoder, GetInterface, SL_IID_METADATAEXTRACTION, &decoderMetadata);
  OpenSL(decoder, GetInterface, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
      &decoderQueue);

  // Initialize the callback structure, used during the decoding.
  CallbackContext callbackContext;
  {
    android::Mutex::Autolock autoLock(callbackLock_);
    callbackContext.pDataBase = pcmData;
    callbackContext.pData = pcmData;
    callbackContext.decoderMetadata = decoderMetadata;
    callbackContext.playItf = decoderPlay;
    RegisterCallbackContextAndAddEnqueueBuffersToDecoder(
        decoderQueue, &callbackContext);
  }

  // Initialize the callback for prefetch errors, if we can't open the
  // resource to decode.
  OpenSL(decoderPrefetch, SetCallbackEventsMask, kPrefetchErrorCandidate);
  OpenSL(decoderPrefetch, RegisterCallback, PrefetchEventCb, &decoderPrefetch);

  // Seek to the start position.
  OpenSL(decoderSeek, SetPosition, startPositionMillis_, SL_SEEKMODE_ACCURATE);

  // Start decoding immediately.
  OpenSL(decoderPlay, SetPlayState, SL_PLAYSTATE_PLAYING);

  // These variables hold the audio player and its output.
  // They will only be constructed once the decoder has invoked the callback,
  // and given us the correct sample rate, number of channels and duration.
  SLObjectItf outputMix = NULL;
  SLObjectItf audioPlayer = NULL;
  SLPlayItf audioPlayerPlay = NULL;
  SLAndroidSimpleBufferQueueItf audioPlayerQueue = NULL;

  // The main loop - until we're told to stop: if there is audio data coming
  // out of the decoder, feed it through the time scaler.
  // As it comes out of the time scaler, feed it into the audio player.
  while (!Finished()) {
    if (GetWasStartRequested() && HasSampleRateAndChannels()) {
      // Build the audio player.
      // TODO: What happens if I maliciously call start lots of times?
      floatBuffer_ = new float[targetFrames_ * mChannels];
      injectBuffer_ = new float[targetFrames_ * mChannels];
      OpenSL(engineInterface, CreateOutputMix, &outputMix, 0, NULL, NULL);
      OpenSL(outputMix, Realize, SL_BOOLEAN_FALSE);
      CreateAndRealizeAudioPlayer(GetSLSampleRate(), GetChannelCount(),
          GetSLChannels(), audioStreamType_, outputMix, audioPlayer,
          engineInterface);
      OpenSL(audioPlayer, GetInterface, SL_IID_PLAY, &audioPlayerPlay);
      OpenSL(audioPlayer, GetInterface, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
          &audioPlayerQueue);
      OpenSL(audioPlayerQueue, RegisterCallback, PlayingBufferQueueCb, NULL);
      ClearRequestStart();
      OpenSL(audioPlayerPlay, SetPlayState, SL_PLAYSTATE_PLAYING);
    }
    EnqueueMoreAudioIfNecessary(audioPlayerQueue);
    usleep(kSleepTimeMicros);
  }

  // Delete the audio player and output mix, iff they have been created.
  if (audioPlayer != NULL) {
    OpenSL(audioPlayerPlay, SetPlayState, SL_PLAYSTATE_STOPPED);
    OpenSL0(audioPlayerQueue, Clear);
    OpenSL(audioPlayerQueue, RegisterCallback, NULL, NULL);
    VoidOpenSL(audioPlayer, AbortAsyncOperation);
    VoidOpenSL(audioPlayer, Destroy);
    VoidOpenSL(outputMix, Destroy);
    audioPlayer = NULL;
    audioPlayerPlay = NULL;
    audioPlayerQueue = NULL;
    outputMix = NULL;
  }

  // Delete the decoder.
  OpenSL(decoderPlay, SetPlayState, SL_PLAYSTATE_STOPPED);
  OpenSL(decoderPrefetch, RegisterCallback, NULL, NULL);
  // This is returning slresult 13 if I do no playback.
  // Repro is to comment out all before this line, and all after enqueueing
  // my buffers.
  // OpenSL0(decoderQueue, Clear);
  OpenSL(decoderQueue, RegisterCallback, NULL, NULL);
  decoderSeek = NULL;
  decoderPrefetch = NULL;
  decoderQueue = NULL;
  OpenSL(decoderPlay, RegisterCallback, NULL, NULL);
  VoidOpenSL(decoder, AbortAsyncOperation);
  VoidOpenSL(decoder, Destroy);
  decoderPlay = NULL;

  // Delete the engine.
  VoidOpenSL(engine, Destroy);
  engineInterface = NULL;

  return true;
}

bool AudioEngine::Finished() {
  if (GetWasStopRequested()) {
    return true;
  }
  android::Mutex::Autolock autoLock(playBufferLock_);
  return playingBuffers_.size() <= 0 &&
      IsDecodeBufferEmpty() &&
      GetEndOfDecoderReached();
}

bool AudioEngine::GetWasStopRequested() {
  android::Mutex::Autolock autoLock(lock_);
  return stopRequested_;
}

bool AudioEngine::GetHasReachedPlayingBuffersLimit() {
  android::Mutex::Autolock autoLock(playBufferLock_);
  return playingBuffers_.size() >= maxPlayBufferCount_;
}

void AudioEngine::EnqueueMoreAudioIfNecessary(
    SLAndroidSimpleBufferQueueItf audioPlayerQueue) {
  bool keepEnqueueing = true;
  while (audioPlayerQueue != NULL &&
         !GetWasStopRequested() &&
         !IsDecodeBufferEmpty() &&
         !GetHasReachedPlayingBuffersLimit() &&
         keepEnqueueing) {
    keepEnqueueing = EnqueueNextBufferOfAudio(audioPlayerQueue);
  }
}

bool AudioEngine::DecodeBufferTooFull() {
  android::Mutex::Autolock autoLock(decodeBufferLock_);
  return decodeBuffer_.IsTooLarge();
}

// ****************************************************************************
// Code for handling the static callbacks.

void AudioEngine::PlayingBufferQueueCallback() {
  // The head playing buffer is done, move it to the free list.
  android::Mutex::Autolock autoLock(playBufferLock_);
  if (playingBuffers_.size() > 0) {
    freeBuffers_.push(playingBuffers_.front());
    playingBuffers_.pop();
  }
}

void AudioEngine::PrefetchEventCallback(
    SLPrefetchStatusItf caller, SLuint32 event) {
  // If there was a problem during decoding, then signal the end.
  SLpermille level = 0;
  SLuint32 status;
  OpenSL(caller, GetFillLevel, &level);
  OpenSL(caller, GetPrefetchStatus, &status);
  if ((kPrefetchErrorCandidate == (event & kPrefetchErrorCandidate)) &&
      (level == 0) &&
      (status == SL_PREFETCHSTATUS_UNDERFLOW)) {
    LOGI("prefetcheventcallback error while prefetching data");
    SetEndOfDecoderReached();
  }
  if (SL_PREFETCHSTATUS_SUFFICIENTDATA == event) {
    // android::Mutex::Autolock autoLock(prefetchLock_);
    // prefetchCondition_.broadcast();
  }
}

void AudioEngine::DecodingBufferQueueCallback(
    SLAndroidSimpleBufferQueueItf queueItf, void *context) {
  if (GetWasStopRequested()) {
    return;
  }

  CallbackContext *pCntxt;
  {
    android::Mutex::Autolock autoLock(callbackLock_);
    pCntxt = reinterpret_cast<CallbackContext*>(context);
  }
  {
    android::Mutex::Autolock autoLock(decodeBufferLock_);
    decodeBuffer_.AddData(pCntxt->pData, kBufferSizeInBytes);
  }

  if (!HasSampleRateAndChannels()) {
    android::Mutex::Autolock autoLock(callbackLock_);
    ReadSampleRateAndChannelCount(pCntxt, &mSampleRate, &mChannels);
  }

  {
    android::Mutex::Autolock autoLock(lock_);
    if (totalDurationMs_ == 0) {
      totalDurationMs_ = ReadDuration(pCntxt->playItf);
    }
    // TODO: This isn't working, it always reports zero.
    // ReadPosition(pCntxt->playItf);
  }

  OpenSL(queueItf, Enqueue, pCntxt->pData, kBufferSizeInBytes);

  // Increase data pointer by buffer size
  pCntxt->pData += kBufferSizeInBytes;
  if (pCntxt->pData >= pCntxt->pDataBase +
      (kNumberOfBuffersInQueue * kBufferSizeInBytes)) {
    pCntxt->pData = pCntxt->pDataBase;
  }

  // If we get too much data into the decoder,
  // sleep until the playback catches up.
  while (!GetWasStopRequested() && DecodeBufferTooFull()) {
    usleep(kSleepTimeMicros);
  }
}

void AudioEngine::DecodingEventCallback(SLPlayItf, SLuint32 event) {
  if (SL_PLAYEVENT_HEADATEND & event) {
    SetEndOfDecoderReached();
  }
}