Explore the integration of media technologies within your app. Discuss working with audio, video, camera, and other media functionalities.

All subtopics

Post

Replies

Boosts

Views

Activity

Outputvolume of AVAudioSession returning rounded values
Using the hardware volume buttons on the iPhone, you have 16 steps you can adjust your volume to. I want to implement a volume control slider in my app. I am updating the value of the slider using AVAudioSession.sharedInstance().outputVolume. The problem is that this returns values rounded to the nearest 0 or 5. This makes the slider jump around. .formatted() is not causing this problem. You can recreate the problem using code below. @main struct VolumeTestApp: App { init() { try? AVAudioSession.sharedInstance().setActive(true) } var body: some Scene { WindowGroup { ContentView() } } } struct ContentView: View { @State private var volume = Double() @State private var difference = Double() var body: some View { VStack { Text("The volume changed by \(difference.formatted())") Slider(value: $volume, in: 0...1) } .onReceive(AVAudioSession.sharedInstance().publisher(for: \.outputVolume), perform: { value in volume = Double(value) }) .onChange(of: volume) { oldValue, newValue in // Only used to make the problem more obvious if oldValue > newValue { difference = oldValue - newValue } else { difference = newValue - oldValue } } } } Here is a video of the problem in action: https://share.icloud.com/photos/00fmp7Vq1AkRetxcIP5EXeAZA What am I doing wrong or what can I do to avoid this? Thank you
1
0
391
Jun ’24
(Audio) WorkGroup in CoreAudio server plugin
Hi, we have multiple threads in our CoreAudio server plugin carrying out necessary asynchronous work (namely handling USB callbacks and shuffling the required data to the IO). Although these threads have been set up with the appropriate THREAD_TIME_CONSTRAINT_POLICY (which actually improves it) - on M* processors there is an extremely high, non-realtime amount of jitter of >10ms(!) Now either the runloop notification from the USB stack comes that late or the thread driving the runloop hasn't been set up to correctly handling the callbacks in a timely manner. Since AudioUnits threads requiring to comply to the frame deadlines can join the workgroup of the audio device is there a similar opportunity for the CoreAudio server plugin threads? And if so, how should these correctly be set up? Thanks for any hints! Or pointing me to the docs :)
0
0
255
Jun ’24
UIImageView is caching all of my images causing memory issues
I'm using a UIImageView to display album artwork when playing music. Every time new artwork is loaded, the memory usage increases. I'm using ARC and tried a autoreleasepool around the code. If I put the app in the background, the cache clears and it starts using up memory again. Here's my code: - (void) showArtwork { @autoreleasepool { MPMediaItem *currentItem = [self.musicPlayer nowPlayingItem]; if (currentItem) { MPMediaItemArtwork *artwork = [currentItem valueForProperty: MPMediaItemPropertyArtwork]; if (artwork) { UIImage *artworkImage = [artwork imageWithSize: CGSizeMake (339, 339)]; if (artworkImage) { [self.appCoverArt setImage: artworkImage]; } } } } } musicPlayer is the systemMusicPlayer appCoverArt is my UIIMageView 1. Is there a way to release an image from UIImageView before assigning a new image? 2. Is there a way to clear the pool other than putting the app in the background (which does clear the memory)?
5
0
342
Jun ’24
Taking a screenshot that includes AVCaptureVideoPreviewLayer
I have an app that displays overlays on top of an AVCaptureVideoPreviewLayer (basically AR without ARKit), and my users have repeatedly requested a button that will allow them to capture a screenshot of both the video and the overlays and surrounding UI with a single tap. However, I cannot find a way to actually take such a screenshot. I have tried the usual methods of rendering views to images, such as calling drawViewHierarchyInRect on my top level view or calling renderInContext on the same view's layer. These all work perfectly to capture the overlays and the surrounding UI elements, but there is nothing but black where the video preview's contents should be. snapshotViewAfterScreenUpdates: does capture exactly what I want, but snapshot views cannot be written to an image. From what I understand that's an intentional security decision by Apple. I've considered using ReplayKit to take a very short screen recording and then using an AVAssetImageGenerator to grab a frame from that video, but I don't think that's how those APIs were intended to be used and it's an additional permission to request from the user. I would really rather not do this if there is any alternative (and I'm not even sure it would work). Is there any reasonable method to render a view hierarchy to an image in such a way as to capture the contents of any video preview layers found within that hierarchy?
0
0
218
Jun ’24
Properly rotate/mirror video in AVCaptureVideoDataOutput and flipping input devices
Hey all, I have a pretty complicated camera setup so bear with me. You know how Instagram's Camera supports recording a video and flipping Camera devices while recording? I built the same thing using AVCaptureVideoDataOutput and it works fine, but it does not support rotation. (neither does Instagram, but I still need it, lol) So there's two ways to implement rotation (and mirroring) in AVCaptureVideoDataOutput: 1. Set it on the AVCaptureConnection Rotation and vertical mirror mode can be set directly on the AVCaptureVideoDataOutput's connection to the Camera: let output = AVCaptureVideoDataOutput(...) cameraSession.addOutput(output) for connection in output.connections { connection.videoRotation = 90 connection.isVideoMirrored = true } But according to the documentation this is expensive and comes with a performance overhead. I haven't really benchmarked it yet, but I assume rotating and mirroring 4k buffers isn't cheap. I'm building a camera library that is used by a lot of people, so all performance decisions have a big impact. 2. Set it on AVAssetWriter Instead of actually physically rotating large pixel buffers, we can also just set the AVAssetWriter's transform property to some affine transformation - which is comparable to how EXIF tags work. We can set both rotation and mirror modes using CGAffineTransforms. Obviously this is much more efficient and does not come with a performance overhead on the camera pipeline at all, so I'd prefer to go this route. Problem The problem is that when I start recording with the front Camera (AVAssetWriter.transform has a mirror on the CGAffineTransform), and then flip to the back Camera, the back Camera is also mirrored. Now I thought I could just avoid rotation on my buffers and only use isVideoMirrored on the AVCaptureConnection when we are using the front camera, which is a fair performance compromise - but this won't work because isVideoMirrored applies mirroring alongside the vertical axis - and since the video stream is naturally in landscape orientation, this will flip the image upside down instead of mirroring it alongside the vertical axis... whoops! 😅 This is pretty obvious as the transform applies to the entire video stream, but now I am not sure if the AVAssetWriter approach will work for my use-case. I think I will need to eagerly physically rotate the pixel buffers by setting the AVCaptureConnection's videoRotation & isVideoMirrored properties, but I wanted to ask here in case someone knows any alternatives to doing that in order to avoid the performance and memory overhead of rotating buffers? Thanks!
0
0
239
Jun ’24
Device Volume Changes After Setting AVAudioSession Category
Hi there, I am encountering an issue in my project which utilizes a speech recognizer and occasionally plays audio files. The problem arises when I configure the AVAudioSession and enable voice processing. The system volume changes unexpectedly and becomes uncontrollable. Specifically, the volume is excessively loud on iPhone but quite low on iPad let audioSession = AVAudioSession.sharedInstance() try audioSession.setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker, .allowBluetooth, .interruptSpokenAudioAndMixWithOthers]) try audioSession.setActive(true, options: .notifyOthersOnDeactivation) try audioEngine.inputNode.setVoiceProcessingEnabled(true) try audioEngine.outputNode.setVoiceProcessingEnabled(true) I have provided a sample project here: Sample Project. To reproduce the issue, please follow these steps on a real device: Click on "Play recording" to hear the sound at normal volume. Click on "Start recording" to set up the category and speech recognizer. Click on "Stop recording" to stop the recording. Click on "Play recording" again and observe that the sound volume has changed. Thank you for your assistance.
0
0
282
Jun ’24
AVAudioSession.interruptionNotification only delivered once
In my app, I only get one interruption notification when a phone call comes in, and nothing after that. The app uses AVAudioEngine. Is this a bug? A very simple repro is to just register for the notification, but not do anything else with audio: struct ContentView: View { var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") } .padding() .onReceive(NotificationCenter.default.publisher(for: AVAudioSession.interruptionNotification)) { event in handleAudioInterruption(event: event) } } private func handleAudioInterruption(event: Notification) { print("handleAudioInterruption") guard let info = event.userInfo, let typeValue = info[AVAudioSessionInterruptionTypeKey] as? UInt, let type = AVAudioSession.InterruptionType(rawValue: typeValue) else { print("missing the stuff") return } if type == .began { print("interruption began") } else if type == .ended { print("interruption ended") guard let optionsValue = info[AVAudioSessionInterruptionOptionKey] as? UInt else { return } if AVAudioSession.InterruptionOptions(rawValue: optionsValue).contains(.shouldResume) { print("should resume") } } } } And do this in the app's init: @main struct InterruptionsApp: App { init() { try! AVAudioSession.sharedInstance().setCategory(.playback, options: []) try! AVAudioSession.sharedInstance().setActive(true) } var body: some Scene { WindowGroup { ContentView() } } }
2
0
379
Jun ’24
On Sonoma 14.5, after upgrading CMIO CameraExtension, daemon is not running
I made CameraExtension and installed by OSSystemExtensionRequest. I got success callback. I did uninstall old version of my CameraExtension and install new version of my CameraExtension. "systemextensionsctl list" command shows "[activated enabled]" on my new version. But no daemon process with my CameraExtension is not running. I need to reboot OS to start the daemon process. This issue is new at macOS Sonoma 14.5. I did not see this issue on 14.4.x
0
0
321
May ’24
USB microphone with high samplerate and AVAudioEngine
Hello, I can't get my head wrapped around the following problem: I have an external USB microphone capable of samplerates of up to 500 kHz. I want to capture the samples and do analysis and display - no playback required. I can not find a way to run the microphone with its maximum samplerate, I always get 48 kHz. I would like to stick to AVAudioEngine if possible. Any pointer welcome. thx! volker
2
0
425
May ’24
How can I cache only the initial few seconds (chunks) of an HLS stream on the disk?
Hi, I am working on an app that is very similar to TikTok in terms of video experience. There is an infinite scroll feed of videos, and I am using HLS URLs as the video source. My requirement is to cache the initial few seconds of each video on the disk while the video is playing. The next time a user views the video, it should play the initial few seconds from the cache, with the subsequent chunks coming from the network. Additionally, when there is no network connection, the video should still play the initial few seconds from the cache. I was able to achieve this with MP4 using AVAssetResourceLoaderDelegate, but the same approach is not possible with HLS. What are some other ways through which I can implement this feature? Thanks.
2
0
294
May ’24
Filtering background process "windows" during capture
I am trying to take a screenshot of each running window on the screen independently (even if not in the foreground). I am using SCScreenshotManager's captureImageWithFilter and SCContentFilter's initWithDesktopIndependentWindow. When I do this for every SCWindow in SCShareableContent's windows, I do get all the actual windows, but also get many mostly blank windows or windows that no ordinary user would consider to be an actual window. These include dozens of windows with no title, some with "Focus Proxy" title, some for menu bar icons, the wallpaper, the desktop icons, etc. I've implemented a naive solution that filters all windows that have no title, owningApplications with no title or bundle ID in a hardcoded blocklist (e.g. "com.apple.controlcenter", "com.apple.wallpaper.agent") and that helps, but is far from robust and is naturally fragile. Is there a recommended way to distinguish actual application windows or an overall better approach here? Thanks!
1
0
282
May ’24
AVFoundation: Strange error while trying to switch camera formats with the touch of a single button.
I'm getting the following output from my iOS app's debug console, note the error on the last line: Capture format keys: ["600x600@25", "1200x1200@5", "1200x1200@30", "1600x1200@2", "1600x1200@30", "3200x2400@15", "3200x2400@2", "600x600@30"] Start capture session for 1600x1200@30: <AVCaptureSession: 0x303c70190 [AVCaptureSessionPresetPhoto]> Stop capture session: <AVCaptureSession: 0x303c70190 [AVCaptureSessionPresetInputPriority]> <AVCaptureDeviceInput: 0x303ebb720 [Medwand S3 Camera]>[vide] -> <AVCaptureVideoDataOutput: 0x303edf1e0> <AVCaptureDeviceInput: 0x303ebb720 [Medwand S3 Camera]>[vide] -> <AVCapturePhotoOutput: 0x303ee3e20> <AVCaptureDeviceInput: 0x303ebb720 [Medwand S3 Camera]>[vide] -> <AVCaptureVideoPreviewLayer: 0x3030b33c0> Start capture session for 600x600@30: <AVCaptureSession: 0x303c70190 [AVCaptureSessionPresetInputPriority]> <AVCaptureDeviceInput: 0x303ebb720 [Medwand S3 Camera]>[vide] -> <AVCaptureVideoDataOutput: 0x303edf1e0> <AVCaptureDeviceInput: 0x303ebb720 [Medwand S3 Camera]>[vide] -> <AVCapturePhotoOutput: 0x303ee3e20> <AVCaptureDeviceInput: 0x303ebb720 [Medwand S3 Camera]>[vide] -> <AVCaptureVideoPreviewLayer: 0x3030b33c0> <<<< FigSharedMemPool >>>> Fig assert: "blkHdr->useCount > 0" at (FigSharedMemPool.c:591) - (err=0) This is in response to trying to switch capture formats between the two key modes that must regularly be used by my application. Below you will find the functions that I use to start and stop capturing frames to my preview layer. I have a UI with three buttons. Off Mode 1 Mode 2 If I tap the Off button in between tapping Mode 1 or Mode 2 all is well; I can do this all day. However, attempt to jump between Mode 1andMode 2` directly I run into issues. I added a layer of software between the UI and the underlying functions so that I could make sure to turn off the Camera before turning it back on in the opposite mode and was surprised to get this output. Can someone at Apple please tell me what is going on here? For the rest of you, if anyone knows the magic incantation to safely switch camera formats, please paste that code here. Thanks. I've included my code below. func start(for deviceFormat: String) { sessionQueue.async { [unowned self] in logger.debug("Start capture session for \(deviceFormat): \(self.captureSession)") do { guard let format = formatDict[deviceFormat] else { throw Error.captureFormatNotFound } captureSession.stopRunning() captureSession.beginConfiguration() // May not be necessary. try captureDevice.lockForConfiguration() // Without this we get an error. captureDevice.activeFormat = format captureDevice.unlockForConfiguration() // Matching function: Necessary. captureSession.commitConfiguration() // Matching function: May not be necessary. captureSession.startRunning() } catch { logger.fault("Failed to start camera: \(error.localizedDescription)") errorPublisher.send(error) } } } func stop() { sessionQueue.async { [unowned self] in logger.debug("Stop capture session: \(self.captureSession)") captureSession.stopRunning() } }
0
0
270
May ’24
Changing CIKernel sampler coord causes chaos
I feel like I'm missing something really simple. I've got the simplest possible CIKernel, it looks like this: extern "C" float4 Simple(coreimage::sampler s) { float2 current = s.coord(); float2 anotherCoord = float2(current.x + 1.0, current.y); float4 sample = s.sample(anotherCoord); // s.sample(current) works fine return sample; } It's (in my mind) incrementing the x position of the sampler by 1 and sampling the neighboring pixel. What I get in practice is a bunch of banded garbage (pictured below.) The sampler seems to be pretty much undocumented, so I have no idea whether I'm incrementing by the right amount to advance one pixel. The weird banding is still present if I clamp anootherCoord to s.extent() but it behaves normally if I sample s.coord() unchanged. I'm trying to write a box blur that samples / averages neighboring pixels and am completely blocked by this. What am I missing?
2
0
345
May ’24
AudioMidi.app / Music.app drift sync
When I connect my MacBook to my living room AirPort (older gen wallwart) via Music app, the music output in both rooms is synced. When I try to setup a Multi-Output Device in AudioMidi setup, I'm not able to get them synced. I'm outputting to the same devices, they're all on the same sample rate, and I've played with the various settings (Primary Clock Source and Drift Sync). What gives? How are these connections different? Intel MacBook Pro 2018 running Sonoma 14.5
1
0
367
May ’24