在不导入自己的情况下播放系统声音

Posted

技术标签:

【中文标题】在不导入自己的情况下播放系统声音【英文标题】:Playing system sound without importing your own 【发布时间】:2011-10-20 05:50:39 【问题描述】:

是否可以在不导入自己的情况下播放已经存在的系统声音?

【问题讨论】:

Xcode 还在其自身中捆绑了模拟器 ios 系统文件。这不同于~/Library/Developer/CoreSimulator(仅限用户空间文件)系统文件在这里:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Audio/UISounds 【参考方案1】:

我发现这个 systemSoundID 列表对于直接访问声音 ID 非常有用。http://iphonedevwiki.net/index.php/AudioServices

例如,播放按键音。

#define systemSoundID    1104
AudioServicesPlaySystemSound (systemSoundID);

您还需要在项目中添加 AudioToolbox 框架,并将 #include <AudioToolbox.h> 添加到您的 .m 或 .h 文件中。

【讨论】:

您显然忘记添加指向实际列表的链接?【参考方案2】:

这段代码播放苹果系统声音“Tock.aiff”..我相信你可以使用它播放不同的系统声音

NSString *path = [[NSBundle bundleWithIdentifier:@"com.apple.UIKit"] pathForResource:@"Tock" ofType:@"aiff"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:path], &soundID);
AudioServicesPlaySystemSound(soundID);
AudioServicesDisposeSystemSoundID(soundID);

见this线程

Apple 关于系统声音的文档

https://developer.apple.com/documentation/audiotoolbox/system_sound_services

【讨论】:

在链接的示例项目中,它在自述文件中明确指出没有可用的系统声音(在 ios4 中)。我不认为使用 uikit 包中的命名文件是一个好主意,因为它可以随时更改。从模拟器包中提取声音并将其包含在您自己的包中的链接线程中的想法更好,即使仍然有点不稳定。 效果很好!只需检查 nil 以免崩溃。 不要立即“处理” soundID,你不会听到任何声音,(至少当我这样做的时候)你必须稍后处理它......如果合适的话,可能在 dealloc 中或 viewDidUnload。 第 3 行给出了这个错误:“将 Objective-C 指针类型 'id' 转换为 C 指针类型 CFURLRef'(又名 'const struct_CFURL *')需要桥接转换”。我在这里找到了解决方案:iosdeveloperzone.com/2012/07/28/...(它是 ARC 的东西。你必须将 (CFURLRef) 更改为 (__bridge CFURLRef))。但“问题”是这样你只能得到 3 个声音。 Tink.aiff、Tock.aiff 和 iPod Click.aiff。有关如何访问(其他)14 个的任何想法,可在 Settings->Sound->Text Tone(例如)获得? 这个答案在 ios 7 中对我不起作用。你可以看看这个:github.com/TUNER88/iOSSystemSoundsLibrary【参考方案3】:

您可以将其用于所有默认系统音频。

例如,对于敲击声音的用户来说:

AudioServicesPlaySystemSound(1104);

对于积极的声音,使用这个:

 AudioServicesPlaySystemSound(1054);

而且,否定的声音使用这个:

 AudioServicesPlaySystemSound(1053);

你可以看到here的完整列表。

【讨论】:

【参考方案4】:

所有系统声音列表:iOSSystemSoundsLibrary

import AVKit 之后,您可以播放所有这些声音:

AudioServicesPlaySystemSound (systemSoundID);

【讨论】:

如果我使用这个声音,我的应用会被 AppStore 禁止吗?它不在公共图书馆中,因此审查起来可能很棘手。 @Josip B. 我从来没有遇到过这段代码的审查问题 @DaniSpringer,我制作了一个基于 TUNER88 的 Objective C 版本的 swift 版本。已更新:github.com/CQH/iOS-Sounds-and-Ringtones @CQH 不知道为什么我从来没有收到你的回复通知:/ 我已经分叉并使用了你的回购。看起来确实缺少一堆东西,或者至少我找不到许多文件名的声音 ID。谢谢!【参考方案5】:

改编自@yannc2021

http://iphonedevwiki.net/index.php/AudioServices

如果你想在 Swift 中使用系统声音

// import this
import AVFoundation

// add this method
required init(coder aDecoder: NSCoder) 
    super.init(coder: aDecoder)


// declared system sound here
let systemSoundID: SystemSoundID = 1104

// to play sound
AudioServicesPlaySystemSound (systemSoundID)

【讨论】:

【参考方案6】:

Swift 4 +

注意:仅在真实设备上试用:

import AVKit
AudioServicesPlaySystemSound(1007);

或者您可以尝试使用 URL 作为 -

let url = URL(fileURLWithPath: "/System/Library/Audio/UISounds/payment_success.caf")
var soundID: SystemSoundID = 0
AudioServicesCreateSystemSoundID(url as CFURL, &soundID)
AudioServicesPlaySystemSound(soundID);

https://github.com/klaas/SwiftySystemSounds/blob/master/README.md

【讨论】:

任何人都可以使用AudioToolbox而不是AVKit来支持早期的iOS版本。 你在哪里找到的? @Daniel 我提到了 GitHub 链接。你也可以通过跳转到定义来检查。 我的意思是你在哪里找到这个CreateSystemSoundID 通过阅读官方文档。 developer.apple.com/documentation/audiotoolbox/…【参考方案7】:

swift可以看complete list of system sounds and ringtones例子。

编辑: 好的,以下是此示例中最重要的代码和平:

    ///The directories where sound files are located.
    let rootSoundDirectories: [String] = ["/Library/Ringtones", "/System/Library/Audio/UISounds"]

    ///Array to hold directories when we find them.
    var directories: [String] = []

    ///Tuple to hold directories and an array of file names within.
    var soundFiles: [(directory: String, files: [String])] = []

    //Starting with the "/Library/Ringtones" & "/System/Library/Audio/UISounds" directories, it looks for other sub-directories just one level lower and saves their relative path in directories array.
    //- URLs: All of the contents of the directory (files and sub-directories).
    func getDirectories() 
        let fileManager: NSFileManager = NSFileManager()
        for directory in rootSoundDirectories 
            let directoryURL: NSURL = NSURL(fileURLWithPath: "\(directory)", isDirectory: true)

            do 
                if let URLs: [NSURL] = try fileManager.contentsOfDirectoryAtURL(directoryURL, includingPropertiesForKeys: [NSURLIsDirectoryKey], options: NSDirectoryEnumerationOptions()) 
                    var urlIsaDirectory: ObjCBool = ObjCBool(false)
                    for url in URLs 
                        if fileManager.fileExistsAtPath(url.path!, isDirectory: &urlIsaDirectory) 
                            if urlIsaDirectory 
                                let directory: String = "\(url.relativePath!)"
                                let files: [String] = []
                                let newSoundFile: (directory: String, files: [String]) = (directory, files)
                                directories.append("\(directory)")
                                soundFiles.append(newSoundFile)
                            
                        
                    
                
             catch 
                debugPrint("\(error)")
            
        
    

    //For each directory, it looks at each item (file or directory) and only appends the sound files to the soundfiles[i]files array.
    //- URLs: All of the contents of the directory (files and sub-directories).
        func loadSoundFiles() 
            for i in 0...directories.count-1 
                let fileManager: NSFileManager = NSFileManager()
                let directoryURL: NSURL = NSURL(fileURLWithPath: directories[i], isDirectory: true)

                do 
                    if let URLs: [NSURL] = try fileManager.contentsOfDirectoryAtURL(directoryURL, includingPropertiesForKeys: [NSURLIsDirectoryKey], options: NSDirectoryEnumerationOptions()) 
                        var urlIsaDirectory: ObjCBool = ObjCBool(false)
                        for url in URLs 
                            if fileManager.fileExistsAtPath(url.path!, isDirectory: &urlIsaDirectory) 
                                if !urlIsaDirectory 
                                    soundFiles[i].files.append("\(url.lastPathComponent!)")
                                
                            
                        
                    
                 catch 
                    debugPrint("\(error)")
                
            
        

该示例在表格视图中显示系统声音文件。声音播放如下函数所示:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) 
        //Play the sound
        let directory: String = soundFiles[indexPath.section].directory
        let fileName: String = soundFiles[indexPath.section].files[indexPath.row]
        let fileURL: NSURL = NSURL(fileURLWithPath: "\(directory)/\(fileName)")
        do 
            model.audioPlayer = try AVAudioPlayer(contentsOfURL: fileURL)
            model.audioPlayer.play()
         catch 
            debugPrint("\(error)")
        
    

其中model.audioPlayer 只是AVAudioPlayer 的一个实例:

///Audio player responsible for playing sound files.
var audioPlayer: AVAudioPlayer = AVAudioPlayer()

【讨论】:

很高兴你喜欢这个 repo。我希望它可以帮助人们。我刚刚将它更新到 Swift 3 和 iOS 10。 @CQH 你可以添加短信声音吗?比如“圈子”? 嗨,@DaniSpringer。不幸的是,我无法处理警报声音文件夹。任何帮助将不胜感激。【参考方案8】:

这个纯可可解决方案使用现有的音频文件来播放声音。 此方法可用于播放任何声音文件。 必须将 AVFoundation.framework 添加到您的框架中。 您将必须定义或删除我使用的自我解释的宏。

我在 AVAudioPlayer 中添加了一个类别如下:

AVAudioPlayer+.h

 #import <AVFoundation/AVAudioPlayer.h>

@interface AVAudioPlayer ( CapSpecs )
+ (AVAudioPlayer*) click;
+ (AVAudioPlayer*) tink;
+ (AVAudioPlayer*) tock;
+ (AVAudioPlayer*) withResourceName: (NSString*) aName;
@end

AVAudioPlayer+.m

 #import "AVAudioPlayer+.h"

@implementation AVAudioPlayer ( CapSpecs )
+ (AVAudioPlayer*) click 
    StaticReturn ( [AVAudioPlayer withResourceName: @"iPod Click"] );

+ (AVAudioPlayer*) tink 
    StaticReturn ( [AVAudioPlayer withResourceName: @"Tink"] );

+ (AVAudioPlayer*) tock 
    StaticReturn ( [AVAudioPlayer withResourceName: @"Tock"] );

+ (AVAudioPlayer*) withResourceName: (NSString*) aName 
    NSBundle* zBundle = [NSBundle bundleWithIdentifier: @"com.apple.UIKit"];
    NSURL* zURL = [zBundle URLForResource: aName withExtension: @"aiff"];
    (void) RaiseIfNil ( nil, zURL, ([SWF @"URL for %@",aName]) );
    NSError* zError = nil;
    AVAudioPlayer* zAudio = [[AVAudioPlayer alloc] initWithContentsOfURL: zURL error: &zError];
    RaiseError ( nil, zError, @"AVAudioPlayer init error" );

#ifdef DEBUG
    //  Apple records the console dump which occurs as a bug in the iOS simulator
    //  all of the following commented code causes the BS console dump to be hidden
    int zOldConsole = dup(STDERR_FILENO);   // record the old console
    freopen("/dev/null", "a+", stderr); // send console output to nowhere
    (void)[zAudio prepareToPlay];       // create the BS dump
    fflush(stderr);             // flush the console output
    dup2(zOldConsole, STDERR_FILENO);   // restore the console output
#endif

    return zAudio;

@end

【讨论】:

【参考方案9】:

对于斯威夫特

import AVFoundation

func play(sound: String) 
        var soundID: SystemSoundID = SystemSoundID()
        let mainBundle = CFBundleGetMainBundle()
        if let ref = CFBundleCopyResourceURL(mainBundle, sound as CFString, nil, nil) 
            AudioServicesCreateSystemSoundID(ref, &soundID);
            AudioServicesPlaySystemSound(soundID);
        

@Krishnabhadra 的实现

【讨论】:

【参考方案10】:

这应该会播放大多数 macOS 系统声音

#include <AudioToolbox/AudioToolbox.h>


for (int i = 0; i < 50; i++) 
    NSLog(@"playing %i", i);
    AudioServicesPlaySystemSound (i);
    [NSThread sleepForTimeInterval:1.0];


【讨论】:

以上是关于在不导入自己的情况下播放系统声音的主要内容,如果未能解决你的问题,请参考以下文章

在不播放音乐的情况下更改应用内的音量

是否可以在不停止 iPod 音乐的情况下播放声音?

Qt:如何在不阻塞主线程的情况下播放声音?

HTML:如何在不缓冲所有声音数据的情况下从 URL 中间文件开始声音播放

Naudio:如何在不停止所有其他声音的情况下正确删除 AsioOut 播放的几种声音中的一种?

如何在 Python 中播放声音?