1

I want to make iOS device as source client to send the audio to icecast server. I have setup the icecast server on localhost successfully. Right now when I send below request to server it creates the mountpoint but only for first 8 sec of the audio, the total length of audio is 25 sec. I know this is because I'm not sending the data in chunks. Below is my request:

let requestString = "http://localhost:8000/"
let url = URL(string: requestString)
let mountPointName = "myMountPoint"

var request = URLRequest(url: url!)
request.httpMethod = "SOURCE /\(mountPointName) ICE/1.0"
request.addValue("SOURCE /mp3test ICE/1.0", forHTTPHeaderField: "SOURCE")
request.addValue("audio/ogg", forHTTPHeaderField: "Content-Type")
request.setValue("Basic c291cmNlOmhhY2ttZQ==", forHTTPHeaderField: "Authorization")
request.setValue("Server name", forHTTPHeaderField: "ice-name")
request.setValue("https://www.google.com", forHTTPHeaderField: "ice-url")
request.setValue("RockTest", forHTTPHeaderField: "ice-genre")
request.setValue("128", forHTTPHeaderField: "ice-bitrate")
request.setValue("0", forHTTPHeaderField: "ice-private")
request.setValue("1", forHTTPHeaderField: "ice-public")
request.setValue("Server description", forHTTPHeaderField: "ice-description")
request.setValue("samplerate=44100;bitrate=128;channels=2", forHTTPHeaderField: "ice-audio-info")
self.recurseivelySendRequest(request)

My recursive function:

func recurseivelySendRequest(_ _request: URLRequest) {
    var request = _request

    do {
        let fileURL = Bundle.main.url(forResource: "mount", withExtension: "ogg")  let data = try Data(contentsOf: fileURL!)
        let inputStream = InputStream(data: data)
        request.httpBodyStream = inputStream
    } catch let error {
        print(error)
    }

   // let dataTask = URLSession.shared.uploadTask(withStreamedRequest: request)
   // dataTask.resume()

   let dataTask = URLSession.shared.dataTask(with: request) { (data, response, error) in

   if (error != nil) {
       print(error ?? "error = unknown")
       return
   }

   print(response ?? "response = unknown")

   do {
      let json = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers)
      print(json)
   } catch let error {
      print(error)
      let str = String.init(data: data!, encoding: String.Encoding.utf8)
      print(str ?? "str = nil")
   }

   self.recurseivelySendRequest(request)
}
        dataTask.resume()
}

The problem with above code is it sends only few part of the audio also If I don't send the request recursively the mountpoint no longer exists and seems it is replacing the data not adding. So what I want is to create the mountpoint once and then write the audio data in chunks.

I also followed Icecast 2: protocol description, streaming to it using

TheTiger
  • 13,264
  • 3
  • 57
  • 82
  • What the heck are you doing there? Your mountpoint is named "mp3test", you indicate content "audio/ogg" and send headers indicating CBR? – TBR Apr 27 '18 at 07:39
  • @TBR Actually I copied it from [this description](https://stackoverflow.com/questions/5215019/icecast-2-protocol-description-streaming-to-it-using-c-sharp/9985297#9985297). – TheTiger Apr 27 '18 at 07:45
  • That description is consistent for sending the old MP3 content aka "audio/mpeg". You changed that. What codec are you using? – TBR Apr 27 '18 at 08:00
  • Oh yes my mistake this was "audio/mpeg"... I'm trying to send the data from a locally stored audio file by converting it into `data`. I'm not encoding it. – TheTiger Apr 27 '18 at 08:06
  • If you claim audio/ogg, but send something else, the server will drop you quickly. One of the reasons I'm prodding this. – TBR Apr 27 '18 at 08:25
  • Probably I'm wrong and I will correct this. But right now I'm able to create the `mountpoint` for initial part of the `audio`. Is it possible to create a `mountpoint` and sending the audio data later whenever I want? – TheTiger Apr 27 '18 at 08:31
  • No, are you sure you understand how Icecast works? Icecast is a **live** streaming server. http://liveice.sourceforge.net/understanding.html It takes a continuous stream of binary data and clients can connect to it and will be served **live** data from that point in time. – TBR Apr 27 '18 at 08:36
  • Okay! But there is no guarantee to stream the audio continuously obviously there will be a lack. And should I have to send the all meta data info every time when audio will be send? I'm confused!! And Unfortunately the link you provided is dead :| – TheTiger Apr 27 '18 at 08:53
  • Works for me, seems it was a transient server problem with SourceForge. - While you can set overrides, each source client connection is supposed to set up Metadata. If you need continuous availability, you can provide a "fallback". For details please see https://icecast.org/docs/icecast-2.4.1/ – TBR Apr 27 '18 at 09:43
  • @TBR Thanks for your valuable time! Finally its working now. – TheTiger May 01 '18 at 08:15
  • @TBR There is a delay in voice upto 5-10 seconds.. any suggestion for this? – TheTiger May 01 '18 at 08:20
  • That kind of delay is par for the course. A minimum delay of around 1 second is expected. 5-10s is normal. Tuning it down to a minimum comes at the expense of connection robustness and requires a well performing network. There are very few reasons to tune it this way. More often it indicates that a different tool/transport should be used. – TBR May 01 '18 at 11:36

1 Answers1

0

I was on wrong path finally I found iOS-Icecast-Client on github. It helps me to make a connection with icecast-server and send the recorder audio to server in chunks. As I have already mentioned that I was able to setup the icecast-server on localhost.

After downloading the above library in AudioProcessor.m file there is a line

ShoutOutputStream_Init("192.x.x.x", 8000, "/stream", "source", "hackme", 0);

Where 192.x.x.x is your wifi ip as you can not use localhost in device to connect it. Also make sure your system and device should be on same wifi connection to reach the network.

8000 is your port defined in icecast.xml.

/stream is mount point name defined in icecast.xml.

And here comes where I spent few hours to get the username and password these are also defined in authentication tag in icecast.xml. I used the default one source and hackme.

0 is whether it is vorbis (0) or a .mp3 (1) file.

Finally I got it working. And Many thanks to gstream79 to provide us such a wonderful library.

TheTiger
  • 13,264
  • 3
  • 57
  • 82