Search code examples
swiftvoippjsip

Pjsip iOS How to transmit sound to receiver side and record it?


func startSipRecording(caller: String, callid: pjsua_call_id) -> (started: Bool, startDate: NSDate?) {
        var status = pj_init()
        if status != PJ_SUCCESS.rawValue {
            return (false, nil)
        }
        cpFec = pjsua_data().cp
        /* Must create a pool factory before we can allocate any memory. */
        pj_caching_pool_init(&cpFec!, &pj_pool_factory_default_policy, 0)
        status = pjmedia_endpt_create(&cpFec!.factory, nil, 1, &med_endpt
        )
        if status != PJ_SUCCESS.rawValue {
            return (false, nil)
        }
        pool = pj_pool_create(&cpFec!.factory, "app", 4000, 4000, nil)
        status = pjmedia_conf_create( pool,        /* pool to use        */
            3,/* number of ports        */
            CLOCK_RATE,
            NCHANNELS,
            SAMPLES_PER_FRAME,
            BITS_PER_SAMPLE,
            0,        /* options            */
            &medconf        /* result            */
        );
        if status != PJ_SUCCESS.rawValue {
            return (false, nil)
        }
        pj_pool_alloc(pool, 3 * MemoryLayout.size(ofValue: (pjmedia_port).self))
        print("Starting recording...")
        let rec = Recording.getNewSipBlanckRecording(callerName: caller)
        let files = FileProvider.getRecordingUrl(fileName: rec.fileName)?.path
        let fileName: pj_str_t = pj_str(convertToChar(files))
        print(status == 0 ? "REecorder has been created." : "\(files ?? "")")
        UserDefaults.standard.set(recorder_id, forKey: current_recorder_id)
        UserDefaults.standard.synchronize()
        /* Create WAVE file writer port. */
        let str = String(cString: fileName.ptr, encoding: .utf8)
        status = pjmedia_wav_writer_port_create(pool,
                                                str,
                                                CLOCK_RATE,
                                                NCHANNELS,
                                                SAMPLES_PER_FRAME,
                                                BITS_PER_SAMPLE,
                                                0, 0,
                                                &file_port)

        if status != PJ_SUCCESS.rawValue {
            return (false, nil)
        }
        var strName = pj_str_t(ptr: convertToChar("recorderName"), slen: 12)
        status = pjmedia_conf_add_port(medconf, pool, file_port, &strName, &recSolt)
        var ci = pjsua_call_info()
        pjsua_call_get_info(callid, &ci)
        var recordPort = pjmedia_conf_port_info()
        pjmedia_conf_get_port_info(medconf, recSolt, &recordPort)

        pjmedia_conf_connect_port(medconf, 0, recordPort.slot, 0)
        guard ci.conf_slot != -1 else { return (false, nil) }
        let portid = pjsua_call_get_conf_port(callid)
        pjmedia_conf_connect_port(medconf, UInt32(portid), recordPort.slot, 0)
        pjsua_conf_connect(portid, pjsua_conf_port_id(recordPort.slot))
        pjsua_conf_connect(0, pjsua_conf_port_id(recordPort.slot))
        pjmedia_conf_adjust_rx_level(medconf, recordPort.slot, 128)
        pjmedia_conf_adjust_tx_level(medconf, recordPort.slot, 128)
        pj_thread_sleep(1000)
        return (true, rec.startDateTime)
    }
    func stopSipRecordingandBeep(isBeep: Bool) -> Bool {
        var status:pj_status_t = 1
        if let medEndPoint = medconf {
            pjmedia_conf_destroy(medEndPoint)
        }
        if let fileport = file_port {
            status = pjmedia_port_destroy(fileport)
        }
        if isBeep {
            if let fileport = file_port_Player {
                status = pjmedia_port_destroy(fileport)
            }
        }
        if let poolobj = pool {
            pj_pool_release(poolobj)
        }
        if let medEndPoint = med_endpt {
            pjmedia_endpt_destroy(medEndPoint)
        }
        if cpFec!.used_size > 0 {
            pj_caching_pool_destroy(&cpFec!)
        }
        pj_shutdown()
        return status == 0 ? true : true
    }
    func play_sound_during_call(file: pj_str_t, callid: pjsua_call_id) -> pj_status_t {
        var status = pj_init()
        if status != PJ_SUCCESS.rawValue {
            return status
        }
        /* Must create a pool factory before we can allocate any memory. */
        let str = String(cString: file.ptr, encoding: .utf8)
        status = pjmedia_wav_player_port_create(pool, str, 20, 0, 0, &file_port_Player);
        if status != PJ_SUCCESS.rawValue {
            return status
        }
        if status != PJ_SUCCESS.rawValue {
            return status
        }
        var ci = pjsua_call_info()
        pjsua_call_get_info(callid, &ci)
        let portid = pjsua_call_get_conf_port(callid)
        var recordPort = pjmedia_conf_port_info()
        pjmedia_conf_get_port_info(medconf, recSolt, &recordPort)

        var strName = pj_str_t(ptr: convertToChar("PlayerName"), slen: 10)
        status = pjmedia_conf_add_port(medconf, pool, file_port_Player, &strName, &playSolt)

        var playPort = pjmedia_conf_port_info()
        pjmedia_conf_get_port_info(medconf, playSolt, &playPort)

        status = pjmedia_conf_connect_port(medconf, playPort.slot, 0, 0)
        status = pjmedia_conf_connect_port(medconf, playPort.slot, recordPort.slot, 0)
        status = pjmedia_conf_connect_port(medconf, playPort.slot, UInt32(portid), 0)
        status = pjsua_conf_connect(pjsua_conf_port_id(playPort.slot), portid)
        pj_thread_sleep(100)
        return status
    }

I have tried the above methods to record and play during the call. I am not getting and beep at the receiver side. And the sound that I am playing is too low at the receiver side. Please look into the above code and help if I am making any mistakes.

I found that recorder id and callinfo.conf_port id is the same. and did not find any way to get the conf_slot in crated media_conf. Please help me I am stuck in this for days.


Solution

  • You should use pjsua file player (pjsua_player*) and pjsua file recorder (pjsua_recorder*) instead.

    Call pjsua_player_create()/pjsua_recorder_create() to create the player/recorder.

    And to get the conf port, you can use pjsua_player_get_conf_port()/pjsua_recorder_get_conf_port().

    You should be able to see the sample implementation on pjsua_app.c