Search code examples
iosswiftstreaminggcdwebservercocoahttpserver

How to stream audio(Device Songs) using cocoahttpserver in swift?


I'm creating application that one device act as server and other devices join, I manage to create server, but I can't find a way to stream audio (Device local songs).

Steps:

  1. i create server with GCDWebServer

  2. get NSData from MPMediaItem

  3. set songData in server Default Get Requests

Here is my code :

class DjSocketServer : NSObject,GCDWebServerDelegate
{
var myLocalServer = GCDWebServer()
var isRunning = false
var serverType = ServerType.isDj


func startServer(with type:ServerType)
{
    serverType = type
    GCDWebServer.setLogLevel(4)
    myLocalServer = GCDWebServer()

    myLocalServer?.delegate = self

    myLocalServer?.addDefaultHandler(forMethod: "GET", request: GCDWebServerRequest.self, processBlock: {request in

        //Default Response to GET request
        if let requestUrl = request?.url.absoluteString
        {
            if requestUrl.contains(".mp3")
            {
                return GCDWebServerDataResponse(data: playerInfo.songPlayedData as Data!, contentType: "audio/mp3")
            }
        }

        let para:NSMutableDictionary = NSMutableDictionary()
        para.setValue(DjInformation.party_name, forKey: "djName")
        para.setValue(Common.DJ_Connected_Users.count, forKey: "listener")
        para.setValue(DjInformation.dj_ip, forKey: "djIp")
        para.setValue("http://\(DjInformation.dj_ip):\(AppConfig.Dj_Port)/atrist_poster", forKey: "djImg")
        para.setValue(DjInformation.artist_name, forKey: "artist")

        let jsonData = try! JSONSerialization.data(withJSONObject: para, options: JSONSerialization.WritingOptions.prettyPrinted)
        return GCDWebServerDataResponse(data: jsonData, contentType: "application/json")
    })

    //myLocalServer?.start(withPort: UInt(ServerPort.DjPort.rawValue), bonjourName: UIDevice.current.name)
    do
    {
    try myLocalServer?.start(options: [GCDWebServerOption_AutomaticallySuspendInBackground:false,GCDWebServerOption_Port:UInt(ServerPort.DjPort.rawValue),GCDWebServerOption_BonjourName:UIDevice.current.name])
        print("\n\n\n\n\n\nSuccess Tag:Started ----- \n\n\n\n\n\n")
    }catch
    {
        print("Error Tag : Starting MainDj Server")
    }
}

func webServerDidStart(_ server: GCDWebServer!) {
    print("Visit \(server.serverURL) in your web browser")
    isRunning = true
}

func webServerDidCompleteBonjourRegistration(_ server: GCDWebServer!) {
    print(" CompleteBonjourRegistration ")
}

func webServerDidStop(_ server: GCDWebServer!) {
    print("\n\n\n\n\n\n\nServer Stoped MainDj\n\n\n\n\n\n\n")
    isRunning = false
}
}

I'm passing MPMediaItem to this function and convert to NSData

class func getSongRawData(item: MPMediaItem,success: @escaping (NSData) -> Void,fail: @escaping (NSError) -> Void) -> Void {

    if let exporter = createSongExporter(item: item) {
        exporter.exportAsynchronously(completionHandler: { () -> Void in
            switch exporter.status {
            case .completed:
                let rawData = NSData(contentsOf: exporter.outputURL!)!
                songUrl_selected = (exporter.outputURL?.absoluteString)!
                //print("UURL : ",exporter.outputURL?.absoluteString ?? "None")
                success(rawData)
            default:
                let e = NSError(
                    domain: "jp.co.faithcreates.Meowziq",
                    code: MusicManagerError.RawDataAccessFailed.rawValue,
                    userInfo: [
                        "exporterStatus": exporter.status.rawValue
                    ])
                fail(e)
            }

            self.removeExportedFile(url: exporter.outputURL! as NSURL)
        })
    } else {
        let e = NSError(
            domain: "jp.co.faithcreates.Meowziq",
            code: MusicManagerError.RawDataAccessFailed.rawValue,
            userInfo: nil
        )
        fail(e)
    }
}

private class func createSongExporter(item: MPMediaItem) -> AVAssetExportSession? {
    if let url = item.assetURL {
        let asset = AVURLAsset(url: url, options: nil)
        let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A)

        exporter?.outputFileType = "com.apple.m4a-audio";

        let docDir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
        let fileName = createExportFileName()
        exporter?.outputURL = NSURL(fileURLWithPath: docDir).appendingPathComponent(fileName)

        return exporter
    } else {
        return nil
    }
}

private class func createExportFileName() -> String {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyyMMddhhmmss"
    let dateString = dateFormatter.string(from: NSDate() as Date)
    return String(format: "%@.m4a", dateString)
    //return String(format: "%@.m4a", "tmp")
}

Solution

  • Save NSData as mp3 file in document directory, then use GCDWebServerFileResponse like below

    let fileResponse = GCDWebServerFileResponse(file: song_filePath) 
    return fileResponse