NS_IMETHODIMP
MediaEngineDefaultAudioSource::Notify(nsITimer* aTimer)
{
  TimeStamp now = TimeStamp::Now();
  TimeDuration timeSinceLastNotify = now - mLastNotify;
  mLastNotify = now;
  TrackTicks samplesSinceLastNotify =
    RateConvertTicksRoundUp(AUDIO_RATE, 1000000, timeSinceLastNotify.ToMicroseconds());

  // If it's been longer since the last Notify() than mBufferSize holds, we
  // have underrun and the MSG had to append silence while waiting for us
  // to push more data. In this case we reset to mBufferSize again.
  TrackTicks samplesToAppend = std::min(samplesSinceLastNotify, mBufferSize);

  AudioSegment segment;
  AppendToSegment(segment, samplesToAppend);
  mSource->AppendToTrack(mTrackID, &segment);

  // Generate null data for fake tracks.
  if (mHasFakeTracks) {
    for (int i = 0; i < kFakeAudioTrackCount; ++i) {
      AudioSegment nullSegment;
      nullSegment.AppendNullData(samplesToAppend);
      mSource->AppendToTrack(kTrackCount + kFakeVideoTrackCount+i, &nullSegment);
    }
  }
  return NS_OK;
}
nsresult
MediaEngineDefaultAudioSource::Start(SourceMediaStream* aStream, TrackID aID,
                                     const PrincipalHandle& aPrincipalHandle)
{
  if (mState != kAllocated) {
    return NS_ERROR_FAILURE;
  }

  mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
  if (!mTimer) {
    return NS_ERROR_FAILURE;
  }

  mSource = aStream;

  // We try to keep the appended data at this size.
  // Make it two timer intervals to try to avoid underruns.
  mBufferSize = 2 * (AUDIO_RATE * DEFAULT_AUDIO_TIMER_MS) / 1000;

  // AddTrack will take ownership of segment
  AudioSegment* segment = new AudioSegment();
  AppendToSegment(*segment, mBufferSize);
  mSource->AddAudioTrack(aID, AUDIO_RATE, 0, segment, SourceMediaStream::ADDTRACK_QUEUED);

  if (mHasFakeTracks) {
    for (int i = 0; i < kFakeAudioTrackCount; ++i) {
      segment = new AudioSegment();
      segment->AppendNullData(mBufferSize);
      mSource->AddAudioTrack(kTrackCount + kFakeVideoTrackCount+i,
                             AUDIO_RATE, 0, segment, SourceMediaStream::ADDTRACK_QUEUED);
    }
  }

  // Remember TrackID so we can finish later
  mTrackID = aID;

  // Remember PrincipalHandle since we don't append in NotifyPull.
  mPrincipalHandle = aPrincipalHandle;

  mLastNotify = TimeStamp::Now();

  // 1 Audio frame per 10ms
#if defined(MOZ_WIDGET_GONK) && defined(DEBUG)
// B2G emulator debug is very, very slow and has problems dealing with realtime audio inputs
  mTimer->InitWithCallback(this, DEFAULT_AUDIO_TIMER_MS*10,
                           nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP);
#else
  mTimer->InitWithCallback(this, DEFAULT_AUDIO_TIMER_MS,
                           nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP);
#endif
  mState = kStarted;

  return NS_OK;
}
void
MediaEngineDefaultAudioSource::NotifyPull(MediaStreamGraph* aGraph,
                                          SourceMediaStream *aSource,
                                          TrackID aID,
                                          StreamTime aDesiredTime,
                                          const PrincipalHandle& aPrincipalHandle)
{
  MOZ_ASSERT(aID == mTrackID);
  AudioSegment segment;
  // avoid accumulating rounding errors
  TrackTicks desired = aSource->TimeToTicksRoundUp(AUDIO_RATE, aDesiredTime);
  TrackTicks delta = desired - mLastNotify;
  mLastNotify += delta;
  AppendToSegment(segment, delta, aPrincipalHandle);
  aSource->AppendToTrack(mTrackID, &segment);
}