1

Is it possible/Is there a way to save an audio stream to a local file? I'm very inexperienced and I dont know where to start -- a point in the right direction would be appreciated.

I'm building an app that streams audio from URLs (eg http://audiostream.mp3). I'd like the user to be able to save audio, to a file, from when they start listening to when they finish. As the audio will be a stream, my concern is that i'm not dealing with a complete mp3 file -- i'm guessing this makes things trickier than simply downloading a complete mp3.

Thanks in advance for your help with this.

6
  • If you can get the whole file, you should be able to trim it. If you're building a streaming app, you should have the ability to decode and save it as mp3. Commented Dec 24, 2015 at 13:41
  • Awesome -- thank you. I'll have a read and report back if i have any questions :) Commented Dec 24, 2015 at 13:45
  • Hi -- i'm still playing around with this method. Need to try and thrash out a few issues first... but i may need to come back to you. Commented Dec 26, 2015 at 13:59
  • This method seems to throw an error :(. Commented Dec 26, 2015 at 21:01
  • 1
    Hi -- sorry, I dont understand what you mean. I dont have a full understanding, that's why i'm asking for guidance ;). Is this something you can help me with? Commented Dec 27, 2015 at 21:24

2 Answers 2

3

You can save live audio stream with indefinite duration. You need to use ResourceLoader and URlSessionDataTask.

It's a bit tricky process, so I will explain step by step:

  1. Making an AVURLAsset:

    let asset = AVURLAsset(url: urlWithCustomScheme) 
  2. Set the delegate:

    asset.resourceLoader.setDelegate(resourceLoaderDelegate, queue: DispatchQueue.main) 
  3. Following delegate function will be called:

    func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool 
  4. Now inside this function we will call a function to start the data request, so that downloading of sound buffer can start:

    func startDataRequest(with url: URL) { var recordingName = "default.mp3" if let recording = owner?.recordingName{ recordingName = recording } fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) .appendingPathComponent(recordingName) let configuration = URLSessionConfiguration.default configuration.requestCachePolicy = .reloadIgnoringLocalAndRemoteCacheData session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil) session?.dataTask(with: url).resume() outputStream = OutputStream(url: fileURL, append: true) outputStream?.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode) outputStream?.open() } 

    as you can see we have opened a output stream. We will use this stream to write buffer to our disk.

  5. Now as we initiated a dataTask with the given URL, we will start receiving data bytes into the delegate function:

    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) 
  6. Now we have started receiving live audio stream. Last piece of the puzzle is to store the audio stream. It is the simplest part. We just create an OutputStream object, open it then append the bytes we are receiving in the above delegate function and thats it, we saved the desired part of the live audio stream.

    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { let bytesWritten = data.withUnsafeBytes{outputStream?.write($0, maxLength: data.count)} print("bytes written :\(bytesWritten!) to \(fileURL)") } 

Here is the source code that I wrote on a blog in Medium, solving the problem that you faced: https://github.com/pandey-mohan/LiveAudioCapture

Sign up to request clarification or add additional context in comments.

Comments

1

You can save the buffered song at the same time when it is played.

 NSData *aData = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.noiseaddicts.com/samples_1w72b820/274.mp3"]]; NSError *aError; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:@"/MyFolder.mp3"]; NSLog(@"%@",dataPath); [aData writeToFile:dataPath atomically:YES]; aPlayer = [[AVAudioPlayer alloc]initWithData:aData error:&aError]; if (aError) { NSLog(@"Erri %@",aError.description); } aPlayer.volume = 1; [aPlayer play]; 

3 Comments

Hi -- i couldn't get this to work. The code sticks on line one (NSData) when using my url. I think it's because the URL is a stream (like a radio broadcast) rather than a complete file (eg a song). What are your thoughts?
What is the size of your audio file?
The URL is an audio stream; therefore i guess it gets bigger the longer you access it.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.