CoreAudio - 如何确定播放aac文件的结尾

2024-01-08

我正在 iPhone 上使用 CoreAudio,但我无法找到如何知道歌曲何时播放完毕。

我放了一个属性监听器kAudioQueueProperty_IsRunning,它在开始播放时有效,但在文件结尾时无效。当我停止 AudioQueue 时它就起作用了......

你有好主意吗 ?

多谢。

PS:我使用的是优秀书籍《iPhone Cool Projects》中的示例代码:http://apress.com/book/downloadfile/4453 http://apress.com/book/downloadfile/4453

Edit :

本书中的代码中有一个错误。该修复需要对 -[AudioPlayer audioRequestDidFinish:] 进行小修改,以便它调用 [queue endOfStream]。


Uli Kusterer 的此类清楚地说明了此功能。

这是标题:

//
//  UKSound.h
//  MobileMoose
//
//  Created by Uli Kusterer on 14.07.08.
//  Copyright 2008 The Void Software. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <AudioToolbox/AudioToolbox.h>


#define kNumberBuffers          2


@class UKSound;


@protocol UKSoundDelegate

@optional
-(void) sound: (UKSound*)sender didFinishPlaying: (BOOL)state;

@end



@interface UKSound : NSObject
{
    AudioFileID                     mAudioFile;
    AudioStreamBasicDescription     mDataFormat;
    AudioQueueRef                   mQueue;
    AudioQueueBufferRef             mBuffers[kNumberBuffers];
    UInt64                          mPacketIndex;
    UInt32                          mNumPacketsToRead;
    AudioStreamPacketDescription *  mPacketDescs;
    BOOL                            mDone;
    id<UKSoundDelegate>             delegate;
    int                             maxBufferSizeBytes;
}

@property (assign) id<UKSoundDelegate> delegate;

-(id)   initWithContentsOfURL: (NSURL*)theURL;

-(void) notifyDelegatePlaybackStateChanged: (id)sender;

-(void) play;


// private:
-(void) audioQueue: (AudioQueueRef)inAQ processBuffer: (AudioQueueBufferRef)inCompleteAQBuffer;

@end

这是实现:

//
//  UKSound.m
//  MobileMoose
//
//  Created by Uli Kusterer on 14.07.08.
//  Copyright 2008 The Void Software. All rights reserved.
//

#import "UKSound.h"


static void UKSoundAQBufferCallback(void *                  inUserData,
                                    AudioQueueRef           inAQ,
                                    AudioQueueBufferRef     inCompleteAQBuffer)
{
    UKSound*    myself = (UKSound*)inUserData;

    [myself audioQueue: inAQ processBuffer: inCompleteAQBuffer];
}


static void UKSoundAQPropertyListenerCallback( void *                  inUserData,
                                                AudioQueueRef           inAQ,
                                                AudioQueuePropertyID    inID)
{
    [(UKSound*)inUserData performSelectorOnMainThread: @selector(notifyDelegatePlaybackStateChanged:) withObject: nil waitUntilDone: NO];
}


@implementation UKSound

@synthesize delegate;

-(id)   initWithContentsOfURL: (NSURL*)theURL
{
    self = [super init];
    if( self )
    {
        maxBufferSizeBytes = 0x10000;
        OSStatus    err = AudioFileOpenURL( (CFURLRef)theURL, kAudioFileReadPermission, 0, &mAudioFile );
        if( err != noErr )
            NSLog(@"Couldn't open AudioFile.");
        UInt32 size = sizeof(mDataFormat);
        err = AudioFileGetProperty( mAudioFile, kAudioFilePropertyDataFormat, &size, &mDataFormat );
        if( err != noErr )
            NSLog(@"Couldn't determine audio file format.");
        err = AudioQueueNewOutput( &mDataFormat, UKSoundAQBufferCallback, self, NULL, NULL, 0, &mQueue );
        if( err != noErr )
            NSLog(@"Couldn't create new output for queue.");

        // We have a couple of things to take care of now
        // (1) Setting up the conditions around VBR or a CBR format - affects how we will read from the file
        // if format is VBR we need to use a packet table.
        if( mDataFormat.mBytesPerPacket == 0 || mDataFormat.mFramesPerPacket == 0 )
        {
            // first check to see what the max size of a packet is - if it is bigger
            // than our allocation default size, that needs to become larger
            UInt32 maxPacketSize;
            size = sizeof(maxPacketSize);
            err = AudioFileGetProperty( mAudioFile, kAudioFilePropertyPacketSizeUpperBound, &size, &maxPacketSize);
            if( err != noErr )
                NSLog(@"Couldn't get max packet size of audio file.");
            if( maxPacketSize > maxBufferSizeBytes ) 
                maxBufferSizeBytes = maxPacketSize;

            // we also need packet descpriptions for the file reading
            mNumPacketsToRead = maxBufferSizeBytes / maxPacketSize;
            mPacketDescs = malloc( sizeof(AudioStreamPacketDescription) * mNumPacketsToRead );
        }
        else
        {
            mNumPacketsToRead = maxBufferSizeBytes / mDataFormat.mBytesPerPacket;
            mPacketDescs = NULL;
        }

        // (2) If the file has a cookie, we should get it and set it on the AQ
        size = sizeof(UInt32);
        err = AudioFileGetPropertyInfo( mAudioFile, kAudioFilePropertyMagicCookieData, &size, NULL );
        if( !err && size )
        {
            char* cookie = malloc( size );
            err = AudioFileGetProperty( mAudioFile, kAudioFilePropertyMagicCookieData, &size, cookie );
            if( err != noErr )
                NSLog(@"Couldn't get magic cookie of audio file.");
            err = AudioQueueSetProperty( mQueue, kAudioQueueProperty_MagicCookie, cookie, size );
            if( err != noErr )
                NSLog(@"Couldn't transfer magic cookie of audio file to qudio queue.");
            free( cookie );
        }

        err = AudioQueueAddPropertyListener( mQueue, kAudioQueueProperty_IsRunning,
                                    UKSoundAQPropertyListenerCallback,
                                    self );
        if( err != noErr )
            NSLog(@"Couldn't register for playback state changes.");

            // prime the queue with some data before starting
        mDone = false;
        mPacketIndex = 0;
        for( int i = 0; i < kNumberBuffers; ++i )
        {
            err = AudioQueueAllocateBuffer( mQueue, maxBufferSizeBytes, &mBuffers[i] );
            if( err != noErr )
                NSLog(@"Couldn't allocate buffer %d.", i);

            UKSoundAQBufferCallback( self, mQueue, mBuffers[i] );

            if( mDone ) break;
        }
    }

    return self;
}


-(void) dealloc
{
    OSStatus err = AudioQueueDispose( mQueue, true );
    err = AudioFileClose( mAudioFile );
    if( mPacketDescs )
        free( mPacketDescs );

    [super dealloc];
}


-(void) play
{
    OSStatus err = AudioQueueStart( mQueue, NULL );
    if( err != noErr )
        NSLog(@"Couldn't start audio queue.");
    else
        [self retain];
}


-(BOOL) isPlaying
{
    UInt32      state = NO,
                size = sizeof(UInt32);
    OSStatus    err = AudioQueueGetProperty( mQueue, kAudioQueueProperty_IsRunning, &state, &size );
    if( err != noErr )
        NSLog(@"Couldn't get play state of queue.");

    return state;
}


-(void) notifyDelegatePlaybackStateChanged: (id)sender;
{
    if( ![self isPlaying] )
    {
            NSLog(@"Insert your functionality here.");
        [delegate sound: self didFinishPlaying: YES];
        AudioQueueStop( mQueue, false );
        [self release];
    }
}


-(void) audioQueue: (AudioQueueRef)inAQ processBuffer: (AudioQueueBufferRef)inCompleteAQBuffer
{
    if( mDone )
        return;

    UInt32 numBytes;
    UInt32 nPackets = mNumPacketsToRead;

    // Read nPackets worth of data into buffer
    OSStatus err = AudioFileReadPackets( mAudioFile, false, &numBytes, mPacketDescs, mPacketIndex, &nPackets, 
                                        inCompleteAQBuffer->mAudioData);
    if( err != noErr )
        NSLog(@"Couldn't read into buffer.");

    if (nPackets > 0)
    {
        inCompleteAQBuffer->mAudioDataByteSize = numBytes;      

        // Queues the buffer for audio input/output.
        err = AudioQueueEnqueueBuffer( inAQ, inCompleteAQBuffer, (mPacketDescs ? nPackets : 0), mPacketDescs );
        if( err != noErr )
            NSLog(@"Couldn't enqueue buffer.");

        mPacketIndex += nPackets;
    }
    else
    {
        UInt32      state = NO,
                    size = sizeof(UInt32);
        OSStatus    err = AudioQueueGetProperty( mQueue, kAudioQueueProperty_IsRunning, &state, &size );

        // I should be calling the following, but it always makes the app hang.
        if( state )
        {
            err = AudioQueueStop( mQueue, false );
            if( err != noErr )
                NSLog(@"Couldn't stop queue.");
                // reading nPackets == 0 is our EOF condition
        }
        mDone = true;
    }
}

@end

当您致电initWithContentsOfURL: (NSURL*)theURL方法,将UKSoundAQPropertyListenerCallback被添加到音频队列中。它被设置为响应kAudioQueueProperty_IsRunning音频队列属性。之后play方法被调用并且文件完成播放,UKSoundAQPropertyListenerCallback被调用,进而调用notifyDelegatePlaybackStateChanged方法。我已向此方法添加了一条 NSLog 消息,以说明文件何时停止播放。

我很乐意分享一个充分演示此功能的 Xcode 项目。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CoreAudio - 如何确定播放aac文件的结尾 的相关文章

  • 多次按下按钮时声音重叠

    当我按下一个按钮 然后按下另一个按钮时 声音会重叠 我该如何解决这个问题 以便在按下另一个声音时第一个声音停止 void playOnce NSString aSound NSString path NSBundle mainBundle
  • 消除录音曲目中当前播放曲目的声音

    我希望使用远程 IO 进行音频录制和播放 我对核心音频的理解很差 因为我遵循惊人的音频开源 http theamazingaudioengine com 到目前为止 我可以使用相同的代码进行录制和播放 现在我尝试通过麦克风录制并通过 iPh
  • 如何在 iOS 4 上获取更新 NSUserDefault?

    我正在开发一个iPhone应用程序 由于多任务 我在iOS4上遇到了问题 此应用程序具有在 Settings bundle 中定义的默认设置 如果我运行我的应用程序 那么我就会离开它 所以它会进入后台 我将更改设置并重新启动应用程序 它退出
  • iOS 4 阻止并保留计数

    我刚刚开始使用街区和 Grand Central Dispatch 有人告诉我 并在苹果文档 http developer apple com library ios documentation cocoa Conceptual Block
  • iPad 上的 MPMoviePlayerController 支持哪些视频格式?

    当您使用 iTunes 将视频与 iPhone 同步时 如果我没记错的话 保存的视频宽度始终不超过 640 像素 iPad 怎么样 iTunes 与 iPad 同步的视频有多大 1024x768 如果视频尺寸低于 1024x768 怎么办
  • 限制 UITextView 或 UITextField 中粘贴的字符串长度

    限制直接输入 UITextView 或 UITextField 的字符串的问题之前已在 SO 上得到解决 iPhone SDK 设置文本字段的最大字符长度 https stackoverflow com questions 433337 i
  • 在 iPhone 上复制并粘贴多种数据表示形式

    当我尝试将多个数据表示放到 iPhone 3 0 的粘贴板上时 遇到了一些问题 我想做的是将数据表示形式和字符串表示形式放到粘贴板上 数据是我自己的数据类型 我用它来复制和粘贴到我的应用程序中 字符串表示形式是一种将应用程序的内容作为大纲复
  • 当 AudioSessionActive 为 NO 时,无法通过硬件按钮控制 AVAudioPlayer 的音量

    我正在构建一个路线导航应用程序 可以播放周期性的简短声音片段 无论屏幕是否锁定 声音都应该播放 应该与其他音乐播放混合 并且应该在播放此音频时使其他音乐闪避 Apple 在 29 20 分钟的 WWDC 2010 session 412 i
  • 如何通过扬声器而不是较弱的耳机扬声器播放音频?

    我正在学习核心音频 由于某种原因 处理图的声音仅通过弱 耳机 播放 当您将设备放在耳边时 而不是通过 iPhone 的常规扬声器播放 这是设置音频会话的代码 但我看不到它在哪里配置音频路由 void setupAudioSession AV
  • iOS 将音频采样率从 16 kHz 转换为 8 kHz

    我尝试将 PCM 音频从 16kHz 转换为 8kHz 只是采样率 没有格式更改 流程看起来很简单 但我不断得到kAudioConverterErr InvalidInputSize insz 来自呼叫AudioConverterFillC
  • 如何在 iPhone 中设置此布局需要一些帮助

    I have Implement Some paint like application For that the Layout is like as below 这里有一个视图和两个按钮 在我的应用程序中 我从 Button2 选择颜色
  • JSON IPHONE:如何发送 JSON 请求并从服务器提取数据?

    我对 JSON 几乎一无所知 我需要仅使用 iPhone 向服务器发送请求并读取来自它的数据 我尝试过使用杰森框架 https github com stig json framework这样做 但在阅读文档后 我无法弄清楚如何构造该对象并
  • iOS-示例中的协议和委托

    好吧 我正在寻找 但没有任何方法对我有用 以下代码基于许多教程和苹果文档 但我无法让它工作 有人可以帮忙吗 代码崩溃于 obj delegatee self 在 B h 类中 respondsToSelector 和 PerformSele
  • iPhone/iPad 的核心文本示例

    我正在寻找 iphone ipad 的核心文本示例 但运气不佳 任何线索将不胜感激 我在 Github 上编写了一个小项目 为 Core Text 提供了 Objective C 包装器 https github com akosma Co
  • iPhone:如何编写减少倒数计时器的代码?

    我想使用显示倒计时器UILabel将从 5 开始并且每秒减少 1 like 5 4 3 2 1 最后当达到 0 时隐藏标签 我尝试使用它进行编码NSTimer scheduledTimerWithTimeInterval但惨败 请帮我 我只
  • OSX AudioUnit SMP

    我想知道是否有人有编写利用多核处理器和 或对称多处理的 HAL AudioUnit 渲染回调的经验 我的场景如下 子类型的单个音频组件kAudioUnitSubType HALOutput 连同它的渲染回调 负责附加合成n具有独立的单独变化
  • pdf文件文本阅读和搜索

    我想从 pdf 文件中读取文本并将文本搜索到 pdf 文件中 这是我知道的链接 这些都帮不了我 使用 Quartz 2D 解析 pdf 时获取文本位置 https stackoverflow com questions 3627745 ge
  • 如何制作全局数组?

    所以 我读了这个帖子 https stackoverflow com questions 1249131 declaring global variables in iphone project 这几乎正是我正在寻找的东西 然而 这不起作用
  • 在 insertMethod 应用程序中使用 Core Data 会崩溃并给出 NSInternalInconsistencyException 并显示错误消息 Context已经有一个协调器

    我正在 xcode 4 2 中的 insertMethod 在 MasterViewController m 类中 实现一个核心数据示例 我的应用程序崩溃了NSInternalInconsistencyException 和错误消息 Con
  • iOS 4.3 上的cameraOverlayView 问题

    我使用带有cameraOverlayView的选择器控制器在相机视图中显示产品的图像 在应用到覆盖层之前 产品图像会调整大小 它在 iOS 4 2 上运行良好 但在 iOS 4 3 上产品图像显示为全尺寸 pickerController

随机推荐

  • 获取 pandas 数据框中包含和不包含 NaN 的所有行

    在 pandas 数据框中分割包含 NaN 和不包含 NaN 的行的最有效方法 input ID Gender Dependants Income Education Married 1 Male 2 500 Graduate Yes 2
  • 正则表达式与嵌套括号匹配

    OK 我不知道是否可以编写这个正则表达式 所以我将从寻求帮助开始 到目前为止我还没有成功 源字符串 convert varchar 8000 lt text as reason 所需的匹配 convert varchar 8000 lt t
  • 如何处理 R 回归中残差中的 NA?

    所以我遇到了一些问题NAa 的残差值lmR 中的横截面回归 问题不在于NA价值观本身 这就是 R 呈现它们的方式 例如 test residuals 1 2 4 5 0 2757677 0 5772193 5 3061303 4 51028
  • 为组创建唯一的 id

    我正在解决一个问题 我必须对相关项目进行分组并为其分配唯一的 ID 我已经用 python 编写了代码 但它没有返回预期的输出 我需要帮助来完善我的逻辑 代码如下 data child list for index row in df it
  • 如何将 EF6 与 ASP.NET Core 1 结合使用

    我创建了一个 ASP NET Core 1 项目并使用 Net Core 1 0 框架 并且想要使用实体框架6 我按照这个教程https docs efproject net en latest platforms aspnetcore n
  • Json (fasterxml) stackoverflow 异常

    当尝试序列化类别时 我遇到了 stackoverflow 例外 警告 StandardWrapperValve dispatcher Servlet service for servlet 调度程序抛出异常 java lang StackO
  • onCreate 正在复制视图

    我正在松散地遵循阳光课程 但遇到了问题 In my MainActivity onCreate方法 它最初称为 protected void onCreate Bundle savedInstanceState mStudentId Uti
  • 无法弄清楚为什么 PHP 没有从 $.ajax 调用接收 POST 数据

    我以前并不是没有做过同样的过程 但我不明白为什么我的 PHP 脚本的 POST 数据是空的 这是我所做的 发现的 我已经验证 ajax 调用的 data 参数具有值 submitSearch 函数和 success 参数中的警报显示搜索变量
  • applyBindings() 太快,在 Ajax 请求完成之前调用

    请考虑以下 ViewModel 片段 var id given1 given2 get testSynUfGet aspx null function data id data id given1 data given1 given2 da
  • 在 Windows 中将 python .py 作为服务启动

    我创建了一个 Windows 服务来启动 py 脚本 sc create Maraschino binPath C HTPC Maraschino maraschino cherrypy py DisplayName Maraschino
  • UITextView firstRectForRange 返回错误的框架

    Edit 简单的解决方案是将所有帧计算从viewDidLoad to viewDidAppear 我很难让以下代码正常工作 该代码返回 UITextView 中给定 NSRange 的第一帧 如果没有换行符 它就可以工作 但是当我在 UIT
  • MonoDevelop 中的调试/跟踪输出

    在 MonoDevelop 中哪里可以看到 System Diagnostics Debug 和 System Diagnostics Trace 输出 我认为它应该出现在 ApplicationOutput 窗口中 但无处可寻 应用程序输
  • 关于图像加载 IE 问题的 JavaScript/jQuery 事件侦听器

    我正在寻找一种方法来为尽可能多的浏览器实现此功能 var image new Image image addEventListener load function alert loaded false image src image url
  • C++ math.h abs() 与我的 abs() 相比有什么不同

    我目前正在用 C 编写一些像向量数学类的 glsl 并且我刚刚实现了一个abs 像这样的函数 template
  • 如何使用 Python 模块 Dragonfly 识别语音?

    我一直在试图弄清楚如何使用 Dragonfly 模块 我查看了文档 但似乎不知道如何使用它 我只想能够识别一些短语并根据这些短语采取行动 是的 这个例子将终止 我已经看过这个特定的例子很多了 它缺少一些关键功能 首先是 pythoncom
  • Apache Spark join 操作的扩展能力较差

    我在 Apache Spark 上运行 join 操作 发现没有弱可扩展性 如果有人能解释这一点 我将不胜感激 我创建两个数据帧 a b 和 a c 并通过第一列连接数据帧 我为 一对一 连接生成数据帧值 另外 我使用相同的分区器来避免随机
  • 文本字段在 iOS 模拟器上不显示键盘

    我试图使用基本文本字段在这里构建一个简单的登录屏幕 但我无法让键盘出现在模拟器中 通过物理键盘输入效果很好 但在 iOS 模拟器中没有可见的键盘 我必须明确打开它还是什么 感觉我在这里错过了一些非常基本的东西 buildLoginScree
  • 封闭件损坏 - 请帮我修复它

    in a 相关问题 https stackoverflow com questions 4584397 javascript countdown clock 4584501我已经发布了这段代码 它几乎可以工作 但计数器却不能 我们可以修复它
  • 如何在 OpenVDB 中对网格进行下采样

    OpenVDB中有什么好的方法可以对体素网格进行下采样吗 例如 我有体素大小为 1 0 的网格 8x8x8 我想要获得体素大小为 2 0 的网格 4x4x4 each voxel of new grid is some interpolat
  • CoreAudio - 如何确定播放aac文件的结尾

    我正在 iPhone 上使用 CoreAudio 但我无法找到如何知道歌曲何时播放完毕 我放了一个属性监听器kAudioQueueProperty IsRunning 它在开始播放时有效 但在文件结尾时无效 当我停止 AudioQueue