Here i am attaching my code and permission screen shot please advice what is the issues here
i Have tried apple developer guideline with this url https://developer.apple.com/documentation/watchkit/playing_background_audio
but still not working.
func play(url : URL) {
if #available(watchOSApplicationExtension 5.0, *) {
do {
WKExtension.shared().isFrontmostTimeoutExtended = true
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category(rawValue: AVAudioSession.Category.playback.rawValue), mode: AVAudioSession.Mode.moviePlayback, options: AVAudioSession.CategoryOptions.duckOthers)
} catch let error {
print("** Unable to set up the audio session: \(error.localizedDescription) **")
// Handle the error here.
return
}
do {
self.player = try AVAudioPlayer(contentsOf: url)
// player!.prepareToPlay()
player?.delegate = self
} catch let error {
print("** Unable to set up the audio player: \(error.localizedDescription) **")
// Handle the error here.
return
}
print("\nPlaying audio!")
self.player?.play()
// Activate and request the route.
audioSession?.activate(options: []) { (success, error) in
print("Success \(success)")
print("error \(String(describing: error))")
guard error == nil else {
print("** An error occurred: \(error!.localizedDescription) **")
// Handle the error here.
return
}
// Play the audio file.
if success {
} else {
print("audio session activation failded")
}
}
} else {
print("alert")
}
}
You need to set the category before the activate option
Code listing below shows all the steps needed to set up the session, activate it, and begin playing.
// Set up the session.
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(AVAudioSession.Category.playback,
mode: .default,
policy: .longForm,
options: [])
} catch let error {
fatalError("*** Unable to set up the audio session: \(error.localizedDescription) ***")
}
// Set up the player.
let player: AVAudioPlayer
do {
player = try AVAudioPlayer(data: audioData)
} catch let error {
print("*** Unable to set up the audio player: \(error.localizedDescription) ***")
// Handle the error here.
return
}
// Activate and request the route.
audioSession.activate(options: []) { (success, error) in
guard error == nil else {
print("*** An error occurred: \(error!.localizedDescription) ***")
// Handle the error here.
return
}
// Play the audio file.
player.play()
}
Related
The main issue here is, when the microphone input is added, the device loses any haptic system sounds.
I setup the audio session here:
let audioSession = AVAudioSession.sharedInstance()
do {
try self.audioSession.setCategory(.playAndRecord, options: .mixWithOthers)
try self.audioSession.setAllowHapticsAndSystemSoundsDuringRecording(true)
try self.audioSession.setActive(true)
} catch { }
I make sure I am using setAllowHapticsAndSystemSoundsDuringRecording.
Though out the app, I am adding the microphone and removing it on-demand:
do {
let microphonePermission = AVCaptureDevice.authorizationStatus(for: AVMediaType.audio)
if microphonePermission != .denied && microphonePermission != .restricted {
let audioDevice = AVCaptureDevice.default(for: AVMediaType.audio)
let audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice!)
if self.session.canAddInput(audioDeviceInput) {
self.session.addInput(audioDeviceInput)
}
else { print("Could not add audio device input to the session.") }
} else {
}
}
catch { print("Could not create audio device input: \(error).") }
As soon as the microphone is added, it loses haptic feedback and system sounds.
I am trying ScreenRecording implementation using Replaykit. It is currently able to record app screen, but when I am putting it in background for device screen recording, then RPScreenRecorder.startCapture callback is not getting called.
let recorder = RPScreenRecorder.shared()
recorder.delegate = self
recorder.startCapture(handler: { (buffer, bufferType, err) in
self.counter = self.counter.advanced(by: 1)
print(self.counter)
// self.assetWriter.write(buffer: buffer, bufferType: bufferType)
}, completionHandler: {
if let error = $0 {
print(error)
}
})
// stop recording
recorder.stopCapture {
if let err = $0 {
print(err)
}
// self.assetWriter.finishWriting()
}
Do we need to allow any permissions for background access.
I am trying to build an audio app for apple watch. But the problem is whenever I keep my hands down , audio will stop playing.
I have turned background mode on as well.
Can anyone please help me with this? I am stuck at this part.
Here is the Code I have used for playing audio.
func play(url : URL) {
do {
if #available(watchOSApplicationExtension 4.0, *) {
WKExtension.shared().isFrontmostTimeoutExtended = true
} else {
// Fallback on earlier versions
}
self.player = try AVAudioPlayer(contentsOf: url)
player!.prepareToPlay()
player?.delegate = self
player?.play()
print("-----------------")
print("Playing Audio")
print("*****************\nCurrent Time \(String(describing: self.player?.currentTime))")
} catch let error as NSError {
self.player = nil
print(error.localizedDescription)
} catch {
print("*************************")
print("AVAudioPlayer init failed")
}
}
Make sure you are trying to play with Audio Data, not Audio URL and have added policy: .longFormAudio in your category setup. As per Apple documentation, these two settings have to be set for audio to play in background mode.
// Set up the session.
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(
.playback,
mode: .default,
policy: .longFormAudio
)
} catch let error {
fatalError("*** Unable to set up the audio session: \(error.localizedDescription) ***")
}
// Set up the player.
let player: AVAudioPlayer
do {
player = try AVAudioPlayer(data: audioData)
} catch let error {
print("*** Unable to set up the audio player: \(error.localizedDescription) ***")
// Handle the error here.
return
}
// Activate and request the route.
session.activate(options: []) { (success, error) in
guard error == nil else {
print("*** An error occurred: \(error!.localizedDescription) ***")
// Handle the error here.
return
}
// Play the audio file.
player.play()
}
I have tested this code and its working with only Bluetooth connectivity in Watch application not in watch speaker.
Simply turning on background mode is not enough. You also need to activate the AVAudioSession.
It's all well documented by Apple here: Playing Background Audio.
Configure and Activate the Audio Session
Before you can play audio, you need to set up and activate the audio session.
session.setCategory(AVAudioSession.Category.playback,
mode: .default,
policy: .longForm,
options: [])
Next, activate the session, by calling the activate(options:completionHandler:) method.
session.activate(options: []) { (success, error) in
// Check for an error and play audio.
}
Ref: https://developer.apple.com/documentation/watchkit/playing_background_audio
Example:
var player: AVAudioPlayer?
let session: AVAudioSession = .sharedInstance()
func prepareSession() {
do {
try session.setCategory(AVAudioSession.Category.playback,
mode: .default,
policy: .longForm,
options: [])
}
catch {
print(error)
}
}
func play(url: URL) {
do {
player = try AVAudioPlayer(contentsOf: url)
}
catch {
print(error)
return
}
session.activate(options: []) { (success, error) in
guard error == nil else {
print(error!)
return
}
// Play the audio file
self.player?.play()
}
}
Simple Test:
prepareSession()
if let url = Bundle.main.url(forResource: "test", withExtension: "mp3") {
play(url: url)
}
else {
print("test.mp3 not found in project: put any mp3 file in and name it so")
}
I am buidling an app using VOIP service. Now i integrated my app with CallKit in order to handle incoming call request.
When the app stays in foreground or background they are working fine when answered call. But the problem is that when the screen is locked and i tried to answer the call but unfortunately I can't hear audio for both side even i unlocked the screen.
How to solve this issue?
This is how incoming call reports:
func reportIncomingCall(uuid: UUID, handle: String, hasVideo: Bool = false, completion: ((NSError?) -> Void)?) {
// 1.
print("This is UUID === ", uuid)
configureAudioSession()
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .phoneNumber, value: handle)
update.hasVideo = hasVideo
provider.reportNewIncomingCall(with: uuid, update: update) { error in
if error == nil {
// 3.
self.configureAudioSession()
let call = CallKitCallInit(uuid: uuid, handle: handle)
self.callKitManager.add(call: call)
lastCallUUID = uuid
print("UUID === ", uuid)
} else {
}
// 4.
completion?(error as NSError?)
}
}
This is how i set audio
func configureAudioSession() {
let session = AVAudioSession.sharedInstance()
do{
try session.setCategory(AVAudioSessionCategoryPlayAndRecord)
} catch {
print("========== Error in setting category \(error.localizedDescription)")
}
do {
try session.setMode(AVAudioSessionModeVoiceChat)
} catch {
print("========= Error in setting mode \(error.localizedDescription)")
}
do {
try session.setPreferredSampleRate(44100.0)
} catch {
print("======== Error setting rate \(error.localizedDescription)")
}
do {
try session.setPreferredIOBufferDuration(0.005)
} catch {
print("======== Error IOBufferDuration \(error.localizedDescription)")
}
do {
try session.setActive(true)
} catch {
print("========== Error starting session \(error.localizedDescription)")
}
}
When i answered the call when screen is locked i could see that the error that it throwed in configureAudioSession() function.
Why it not able to set audio when the screen is locked?
I did by adding these lines of code
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
// 1.
guard let call = callKitManager.callWithUUID(uuid: action.callUUID) else {
action.fail()
return
}
// 2.
configureAudioSession()
// 3.
call.answer()
// 4.
action.fulfill()
}
This is configureAudioSession
func configureAudioSession() {
let session = AVAudioSession.sharedInstance()
do{
try session.setCategory(AVAudioSession.Category.playAndRecord,
mode: AVAudioSession.Mode.voiceChat,
options: [])
} catch {
print("========== Error in setting category \(error.localizedDescription)")
}
do {
try session.setPreferredSampleRate(44100.0)
} catch {
print("======== Error setting rate \(error.localizedDescription)")
}
do {
try session.setPreferredIOBufferDuration(0.005)
} catch {
print("======== Error IOBufferDuration \(error.localizedDescription)")
}
do {
try session.setActive(true)
} catch {
print("========== Error starting session \(error.localizedDescription)")
}
}
You can try using AVAudioSessionModeVoiceChat instead of AVAudioSessionModeMoviePlayback mode while configuring audio session.
i have an app which should record audio when a button i pressed.
In my ViewDidLoad i preapare the recorder, the problem is that streaming audio interrupts when the line 'self.audioRecorder.prepareToRecord()' is called.
My setup :
do {
recordingSession = AVAudioSession.sharedInstance()
try recordingSession.setCategory(AVAudioSessionCategoryRecord, withOptions: [.DuckOthers, .AllowBluetooth, .MixWithOthers])
recordingSession.requestRecordPermission() { [unowned self] (allowed: Bool) -> Void in
dispatch_async(dispatch_get_main_queue()) {
do {
if allowed {
self.audioRecorder = try AVAudioRecorder(URL: self.tempAudioPath, settings: self.settings)
self.audioRecorder.delegate = self
self.audioRecorder.prepareToRecord()
//self.audioRecorder.record()
} else {
// failed to record!
print("No Access to Micro")
}
}catch{}
}
}
} catch {
print (error)
}
is there a way to preapare the audio recorder for record, and continue to play audio in background ? (duck it when recording the audio)
Per Apple's documentation for AVAudioSessionCategoryRecord, "this category silences playback audio". Have you tried setting the category to AVAudioSessionCategoryPlayAndRecord?