I want to play the keyboard 'click' sound when pressing buttons in my app.
How do I access this sound clip with Monotouch? I don't want to pass my own sound using AudioToolbox SystemSound.FromFile(). So far all my searches have led to this solution or Objective-C code using 'AudioServicesCreateSystemSoundID' which I'm having trouble translating to C#.
With iOS 7.0 and higher, Stephane Delcroix answer seems not to work anymore...
But you can easily find the path to all the sounds in this nice project:
https://github.com/TUNER88/iOSSystemSoundsLibrary
Here is the code I used und iOS 7 (take care, it might not work with the simulator!)
private const string NotificationSoundPath = #"/System/Library/Audio/UISounds/New/Fanfare.caf";
public static void TriggerSoundAndViber()
{
SystemSound notificationSound = SystemSound.FromFile(NotificationSoundPath);
notificationSound.AddSystemSoundCompletion(SystemSound.Vibrate.PlaySystemSound);
notificationSound.PlaySystemSound();
}
Also the using() construct in the answer above caused trouble in my case... it seems like it released the sound too early, I only can hear it (and even then not complete with viber) with a breakpoint on PlaySystemSound().
Well, that's not a 1:1 port from the code in Playing system sound without importing your own, but this should do the work:
var path = NSBundle.FromIdentifier ("com.Apple.UIKit").PathForResource ("Tock", "aiff");
using (var systemSound = new SystemSound (NSUrl.FromFilename (path))) {
systemSound.PlaySystemSound ();
}
SystemSound is defined in MonoTouch.AudioToolbox. Make sure to also look at MonoTouch Play System Sound and MonoTouch: Playing sound
Related
So I am following through an old tutorial and I think with the changes in xcode and swift this code is now no longer usable, but i am not sure. Would love some help.
Declaring constant for the audio effect
let cannonSound = SKAction.playSoundFileNamed("cannon.wav", waitForCompletion: false)
Calling the audio effect within my funtion
let hotdogSequence = SKAction.sequence([cannonSound, moveHotdog, deleteHotdog])
hotdog.run(hotdogSequence)
For more info I am using SpriteKit in Xcode and this code is contained within GameScene.swift file.
Update:
The error I receive is
2017-03-30 00:52:43.631 Ballpark Weiner[95999:1983181] SKAction: Error loading sound resource: "cannon.wav"
The game doesn't crash just no sound plays
This message usually means that the file cannot be found in your project or might be corrupt.
You should check that the file is actually copied into your project and is spelled correctly. Its case sensitive so if the actual file is called "Cannon.wav" it will not work.
Hope this helps
I am in the process of developing a game for iOS 9+ using Sprite Kit and preferably using Swift libraries.
Currently I'm using a Singleton where I preload my audio files, each connected to a separate instance of AVAudioPlayer.
Here's a short code-snipped to get the idea:
import SpriteKit
import AudioToolbox
import AVFoundation
class AudioEngine {
static let sharedInstance = AudioEngine()
internal var sfxPing: AVAudioPlayer
private init() {
self.sfxPing = AVAudioPlayer()
if let path = NSBundle.mainBundle().pathForResource("ping", ofType: "m4a") {
do {
let url = NSURL(fileURLWithPath:path)
sfxPing = try AVAudioPlayer(contentsOfURL: url)
sfxPing.prepareToPlay()
} catch {
print("ERROR: Can't load ping.m4a audio file.")
}
}
}
}
This Singleton is initialised during app start-up. In the game-loop I then just call the following line to play a specific audio file:
AudioEngine.sharedInstance.sfxPing.play()
This basically works, but I always get glitches when a file is played and the frame rate drops from 60.0 to 56.0 on my iPad Air.
Someone any idea how to fix this performance issue with AVAudioPlayer ?
I also watched out for 3rd party libraries, namely:
AudioKit [Looks very heavy-weighted]
ObjectAL [Last Update 2013 ...]
AVAudioEngine [Based on AVAudioPlayer, same problems ?]
Requirements:
Play a lot of very short samples (like shots, hits, etc..)
Play some motor effects (thus pitching would be nice)
Play some background / ambient sound in a loop
NO nasty glitches / frame rate drops !
Could you recommend any of the above mentioned libraries for my requirements or point out the problems using the above code ?
UPDATE:
Playing short sounds with:
self.runAction(SKAction.playSoundFileNamed("sfx.caf", waitForCompletion: false))
does indeed improve the frame rate. I exported the audio files with Audiacity to the .caf format (Apple's Core Audio Format). But in the tutorial, they export with "Signed 32-bit PCM" encoding which led to disturbed audio playback in my case. Using any of the other encoding options (32-bit float, U-Law, A-Law, etc..) worked fine for me.
Why using caf format? Because it's uncompressed and thus loaded faster into memory with less CPU overhead compared to compressed formats like m4a. For short sound effects played a lot in short intervals, this makes sense and disk usage is not affected much for short audio files consuming few kilobytes. For bigger audio files, like ambient and background music, using compressed formats (mp3, m4a) is obviously the better choice.
According to your question, if you develop a game for iOS 9+, you can use the new iOS 9 library SKAudioNode (official Apple doc):
var backgroundMusic: SKAudioNode!
For example you can add this to didMoveToView():
if let musicURL = NSBundle.mainBundle().URLForResource("music", withExtension: "m4a") {
backgroundMusic = SKAudioNode(URL: musicURL)
addChild(backgroundMusic)
}
You can also use to play a simple effect:
let beep = SKAudioNode(fileNamed: "beep.wav")
beep.autoplayLooped = false
self.addChild(beep)
Finally, if you want to change the volume:
beep.runAction(SKAction.changeVolumeTo(0.4, duration: 0))
Update:
I see you have update your question speaking about AVAudioPlayer and SKAction. I've tested both of them for my iOS8+ compatible games.
About AVAudioPlayer, I personally use a custom library maked by me based from the old SKTAudio.
I see your code, about AVAudioPlayer init, and my code is different because I use:
#available(iOS 7.0, *)
public init(contentsOfURL url: NSURL, fileTypeHint utiString: String?)
I don't know if fileTypeHint make the difference, so try and fill me about your test.
Advantages about your code:
With a shared instance audio manager based to AVAudioPlayer you can control volume, use your manager wherever you want, ensure compatibility with iOS8
Disadvantages about your code:
Everytime you play a sound and you want to play another sound, the previous is broken, especially if you have launch a background music.
How to solve? According with this SO post to work well without issues seems AVFoundation is limited to 4 AVAudioPlayer properties instantiables, so you can do this:
1) backgroundMusicPlayer: AVAudioPlayer!
2) soundEffectPlayer1: AVAudioPlayer!
3) soundEffectPlayer2: AVAudioPlayer!
4) soundEffectPlayer3: AVAudioPlayer!
You could build a method that switch through the 3 soundEffect to see if is occupied:
if player.playing
and use the next free player. With this workaround you have always your sound played correctly, even your background music.
When I load the Video url in MPMovieplayercontroller in Similator
the log is printing like this what can I do now.
_itemFailedToPlayToEnd: {
kind = 1;
new = 2;
old = 0;
}
So, that the Video is not Viewing in my player
help me..
There could be some problems with your url...
Your url could have spaces. Fill the spaces - stringByAddingPercentEscapesUsingEncoding.
Try changing the source type of the player this might help.
movieplayer. movieSourceType = // source type.
Try running app on a device also sometimes might be the problem due to simulator.
First try on real device if it doesnot work try the above 2 suggestions.
Just a word of warning since I battled this problem for 2 hours and it turned out to be something really simple and quite surprising.
MPMoviePlayerViewController in iOS7 cannot play mov files. In iOS8, however, it works fine.
I'm aware that this is a question already asked, I've found possible duplicates:
Detecting if headphones are plugged into iPhone
headphone plug-in plug-out event when audio route doesn't change - iOS
Detect if headphones (not microphone) are plugged in to an iOS device
...and more info on the WWW. But I've tried out every solution given and everytime I have problem, probably because they are old threads and are referring to iOS 4.
How can I detect it on iOS 5.0?
Thanks
If you're okay with an iOS 6-only solution, Apple added several new AVAudioSession properties that let you detect audio routes in just a few lines (and without the use of C).
Use this method to check for headphones (or adjust it to check for other outputs - "Speaker", "Headset", etc.):
- (BOOL)isHeadsetPluggedIn
{
// Get array of current audio outputs (there should only be one)
NSArray *outputs = [[AVAudioSession sharedInstance] currentRoute].outputs;
NSString *portName = [[outputs objectAtIndex:0] portName];
if ([portName isEqualToString:#"Headphones"]) {
return YES;
}
return NO;
}
If you want to respond to audio route changes passively, you can do this with the new NSNotification, AVAudioSessionRouteChangeNotification. Unfortunately, this notification doesn't tell you what the new route is, just the previous route that it switched from. But, you can just call some variation of the method above to get the current route.
Wes seems to have a great solution. Alas it is not international-proof. This code only works for the English language. In Dutch, for instance, the headset is called 'Koptelefoon' and
*portName
contains indeed 'Koptelefoon' which makes the test fail.
This will do the job internationally correct:
if ([portDescription.portType isEqualToString:AVAudioSessionPortHeadphones])
;
My understanding currently is that:
CameraUI
I can use the CameraUI to access the built in camera for MediaType.VIDEO and that delegates to the built-in video camera app and lets me record a video. My app does that now.
When I stop recording and click the "Use" button, I am returned to my app and theoretically I have a valid MediaPromise.
iOS does -not- provide a valid/usable url/filename to the recorded video (or to photos) and so I would have to use a Loader to bring-in/use/access the 'recorded' video... AND... iOS does not actually create a file anywhere on the device, most importantly, in the Camera Roll where one would expect by the normal behavior when uses the system native camera/video app.
The documentation says that the Loader can load various image types and SWFs but nothing about video data, so I conclude from that that I cannot actually use the CameraUI to generate a valid MediaPromise that I can then pass to a Loader class or similar to read in the information created by the system camera and then manipulate (upload, save to applicationStorageDirectory, and/or display in one of the two video player components available in the API).
CameraRoll
I can have video entities in the iOS Camera Roll but the AS3/Air3.5 CameraRoll class won't let me view/access/reference them in any way.
Normal File I/O
All my attempts to use the Air3.5 File classes to browse to the storage location of the iOS Camera Roll have been rebuffed.
------- Questions -------
Am I correct in believing that there is a way to take video but no way to use the video that's been captured. (No way to use the resulting MediaPromise successfully).
I believe you can take video and access it using Android, but there's nothing in the documentation that says that you cannot using iOS.
Am I correct in believing that iOS sandboxes apps so that they cannot browse to video/photo storage using standard File I/O, but only through the apparently non-workable means I've tried (CameraUI & CameraRoll)
Am I wrong to think that these should be rather obvious NEEDS that one can achieve using the XCode Objective C++ etc route but the AIR Mobile Framework does not allow either because of Apple blocking functionality or because Adobe has failed to meet reasonable expectations?
One item of ironic note to convey. If I use the iOS system camera app to record a video, a thumnail of that video then appears in the Gallery/Camera Roll, and of course, I can share it or view it, or whatever... If I use AIR's CameraRoll.browseForImage(), provided I haven't used the camera to take another image, when it shows me the folder where the pictures are stored, the folder icon uses the thumbnail of the last object added... in this case, the video I took, but if I then enter the folder, the video cannot be found. It's teasing us. It knows it's there, but it is apparently forbidden fruit.
I can't answer all your questions, so this entry may not be acceptable, but I found this page while searching a solution for some the problems you described and thought that someone else may find this answer (partially) useful.
To save the movie you just took you need to open and read the data from the promise.
The iOS won't save the file anywere, so the MediaPromise.file is always null.
This is my solution to the problem:
private var camera:CameraUI;
private var dataInput:IDataInput;
public function recordVideo():void
{
// Start the camera and ask for a video
camera = new CameraUI();
camera.addEventListener(MediaEvent.COMPLETE, onCameraComplete);
camera.launch(MediaType.VIDEO);
}
private function onCameraComplete(event:MediaEvent):void
{
// event.data is a MediaPromise and MediaPromise.open() returns a IDataInput
// Let's cast it to a dispatcher and check when it's complete
dataInput = event.data.open();
var dispatcher:IEventDispatcher = IEventDispatcher(dataInput);
dispatcher.addEventListener(Event.COMPLETE, onDataInputComplete);
}
private function onDataInputComplete(event:Event):void
{
// We can do whatever we want with the data, so we'll store it in a File
var file:File = new File();
var bytes:ByteArray = new ByteArray();
var stream:FileStream = new FileStream();
// Reading the data from the opened MediaPromise
dataInput.readBytes(bytes);
stream.open(file, FileMode.WRITE);
stream.writeBytes(bytes, 0, bytes.bytesAvailable);
stream.close();
}
Also, I'm still looking for a way to put the movie in the CameraRoll