如何暂停,停止和重置AUFilePlayer?

问题描述:

我正在使用AUFilePlayer将核心音频加载到混音器单元中,一切都很棒,但我无法暂停音乐或将音乐倒带回去。我尝试了启动和停止AudioGraph,但是一旦播放停止,我无法重新启动它。如何暂停,停止和重置AUFilePlayer?

 ScheduledAudioFileRegion rgn; 
     memset (&rgn.mTimeStamp, 0, sizeof(rgn.mTimeStamp)); 
     rgn.mTimeStamp.mFlags = kAudioTimeStampSampleTimeValid; 
     rgn.mTimeStamp.mSampleTime = 0; 
     rgn.mCompletionProc = NULL; 
     rgn.mCompletionProcUserData = NULL; 
     rgn.mAudioFile = inputFile; 
     rgn.mLoopCount = 1; 
     rgn.mStartFrame = 0; 

     rgn.mFramesToPlay = nPackets * inputFormat.mFramesPerPacket; 

     AudioUnitSetProperty(fileUnit, kAudioUnitProperty_ScheduledFileRegion, 
          kAudioUnitScope_Global, 0,&rgn, sizeof(rgn)); 

任何建议:我使用AudioUnitSetProperty设置文件播放到0

即东西沿着这些线路也试过吗?

+0

我也尝试AudioUnitReset,但是这并不缝也工作。 – Beleg 2012-07-18 18:47:29

我想通了。在任何情况下,你曾经遇到同样的问题,这里是我的解决方案:

  1. 在启动时,我初始化AUGraph用的文件播放音频单元的阵列。我将文件播放器音频单元阵列中每个轨道的播放头设置为零。

  2. 关于“暂停”,首先停止AuGraph。然后我遍历文件播放器音频单元阵列并捕获当前播放头位置。每次按下暂停按钮时,我都会确保将新的当前播放头位置添加到旧的播放头位置以获得其真实位置。

  3. 当用户点击播放时,我重新初始化AuGraph,就像我第一次启动应用程序一样,只有当播放头设置为我在用户点击“暂停”时存储的号码而不是告诉它在文件开始时播放。

  4. 如果用户单击停止,我将存储的播放头位置设置为零,然后停止AuGraph。

+0

点2非常重要。这正是我所错过的,导致我回到这个问题。在测试时也不要使用重复性的乐器歌曲,很难判断您的暂停是否真正起作用! – Brett 2014-03-08 00:12:28

万一别人是处理类似的问题,这花了我几个小时,在谷歌搜索,这里是我如何专门检索和设置播放头发现了什么。

要从AUFilePlayer单元获得播放头:

AudioTimeStamp timestamp; 
UInt32 size = sizeof(timestamp); 
err = AudioUnitGetProperty(unit, kAudioUnitProperty_CurrentPlayTime, kAudioUnitScope_Global, 0, &timestamp, &size); 

timestamp.mSampleTime是该文件的当前播放头。将mSampleTime转换为浮点数或双精度值,然后除以文件的采样率转换为秒。

对于重新启动AUFilePlayer的播放头,我有一个更复杂的场景,其中多个AUFilePlayers通过调音台,并且可以在不同的时间,多次和不同的循环次数进行调度。这是一个真实世界的场景,让他们在正确的时间重新启动需要一点点代码。

有每个AUFilePlayer四种方案,它的时间表:

  1. 播放头是开头,所以可以正常调度。

  2. 播放头超过了该项目的持续时间,并且根本不需要安排。

  3. 播放头在项目启动之前,所以启动时间可以向上移动。

  4. 播放头处于播放项目的中间位置,因此需要调整文件中播放的区域,并且剩余的循环需要单独安排(以便它们全部播放)。

下面是一些代码,演示了这种(一些外部结构是从我自己的代码,而不是核心音频,但其作用机理应该清楚):

// Add each region 
for(int iItem = 0; iItem < schedule.items.count; iItem++) { 
    AEFileScheduleItem *scheduleItem = [schedule.items objectAtIndex:iItem]; 

    // Setup the region 
    ScheduledAudioFileRegion region; 
    [file setRegion:&region schedule:scheduleItem]; 

    // Compute where we are at in it 
    float playheadTime = schedule.playhead/file.sampleRate; 
    float endOfItem = scheduleItem.startTime + (file.duration*(1+scheduleItem.loopCount)); 

    // There are four scenarios: 

    // 1. The playhead is -1 
    // In this case, we're all done 
    if(schedule.playhead == -1) { 
    } 

    // 2. The playhead is past the item start time and duration*loopCount 
    // In this case, just ignore it and move on 
    else if(playheadTime > endOfItem) { 
     continue; 
    } 

    // 3. The playhead is less than or equal to the start time 
    // In this case, simply subtract the playhead from the start time 
    else if(playheadTime <= scheduleItem.startTime) { 
     region.mTimeStamp.mSampleTime -= schedule.playhead; 
    } 

    // 4. The playhead is in the middle of the file duration*loopCount 
    // In this case, set the start time to zero, adjust the loopCount 
    // startFrame and framesToPlay 
    else { 

     // First remove the start time 
     region.mStartFrame = 0; 
     double offsetTime = playheadTime - scheduleItem.startTime; 

     // Next, take out any expired loops 
     int loopsExpired = floor(offsetTime/file.duration); 
     int fullLoops = region.mLoopCount - loopsExpired; 
     region.mLoopCount = 0; 
     offsetTime -= (loopsExpired * file.duration); 

     // Then, adjust this segment of a loop accordingly 
     region.mStartFrame = offsetTime * file.sampleRate; 
     region.mFramesToPlay = region.mFramesToPlay - region.mStartFrame; 

     // Finally, schedule any remaining loops separately 
     if(fullLoops > 0) { 
      ScheduledAudioFileRegion loops; 
      [file setRegion:&loops schedule:scheduleItem]; 
      loops.mStartFrame = region.mFramesToPlay; 
      loops.mLoopCount = fullLoops-1; 
      if(![super.errors check:AudioUnitSetProperty(unit, kAudioUnitProperty_ScheduledFileRegion, kAudioUnitScope_Global, 0, &region, sizeof(region)) 
          location:@"AudioUnitSetProperty(ScheduledFileRegion)"]) 
       return false; 
     } 
    } 

    // Set the region 
    if(![super.errors check:AudioUnitSetProperty(unit, kAudioUnitProperty_ScheduledFileRegion, kAudioUnitScope_Global, 0, &region, sizeof(region)) 
        location:@"AudioUnitSetProperty(ScheduledFileRegion)"]) 
     return false; 
} 
+1

Smack Jack,你有没有遇到一个问题,你保存的戏剧头部位置零星时间0.5-1秒之前,那么你认为它是?换句话说,你按了暂停,然后当你暂停时,音轨文件/循环开始时间稍早,那么当你第一次按下暂停按钮时? – Beleg 2013-05-03 18:53:46

+1

@Beleg我没有注意到这一点,但我怀疑如果你不先停止图形,那么查询一个或多个项目所需的时间可能会抛弃它,正如其他人在这里讨论的[list.apple.com ](http://lists.apple.com/archives/coreaudio-api/2012/Jul/msg00139.html)。然而,如果没有其他的事情发生,整整一秒的时间看起来会非常糟糕。 – 2013-05-04 23:56:32

+0

因为我首先停止了AuGraph,所以还有其他一些事情正在进行。我在另一个堆栈溢出问题中问了这个问题,并创建了一个赏金,希望有人知道答案。 – Beleg 2013-05-08 03:40:56