桌面和Android之间的IP语音

时间:2017-03-13 16:11:31

标签: java android sockets voip

我正在尝试在Android和桌面之间实时传输音频。我开发了应用程序,一个用于android,一个用于桌面。 桌面应用程序成功地在两个桌面之间进行实时音频传输,并且android应用程序成功地用于两个Android设备之间的音频传输。 我正在使用本地IP地址和端口进行此过程(在两个应用程序中)。

问题是当我尝试在Android和桌面之间传输音频(使用相同的应用程序)时,它无法正常工作。 我只能传输单向音频,例如在台式机接收语音或传输音频时。

请帮助

这是Android应用程序的代码

    package com.example.myrtpapplication;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.net.rtp.AudioCodec;
import android.net.rtp.AudioGroup;
import android.net.rtp.AudioStream;
import android.net.rtp.RtpStream;
import android.os.Handler;
import android.os.StrictMode;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Enumeration;

public class MainActivity extends AppCompatActivity {

    EditText remote_ip_editText;
    EditText remote_port_editText;
    TextView locolport;
    AudioStream audioStream;
    AudioGroup audioGroup;
    String localip;
    Handler handler;
    int flag=0;
    private static int REQUEST_EXTERNAL_STORAGE=1;
    private String[] PERMISSIONS={
            Manifest.permission.RECORD_AUDIO,
            Manifest.permission.MODIFY_AUDIO_SETTINGS,
            Manifest.permission.INTERNET,

    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        verifyPermissions(MainActivity.this);
        if(flag==1) {
            locolport = (TextView) findViewById(R.id.lp);
            remote_ip_editText = (EditText) findViewById(R.id.remote_ip);
            remote_port_editText = (EditText) findViewById(R.id.remote_port);
            handler = new Handler();

            StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
            StrictMode.setThreadPolicy(policy);

            int line = 0;
            try {

                AudioManager audiomanager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
                audiomanager.setMode(AudioManager.MODE_IN_COMMUNICATION);
                audiomanager.setSpeakerphoneOn(true);
                //  audiomanager.adjustStreamVolume(AudioManager.STREAM_VOICE_CALL, AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
                if (audiomanager.isMicrophoneMute()) {
                    Toast.makeText(MainActivity.this, "Microphone is mute", Toast.LENGTH_LONG).show();
                }

                audioGroup = new AudioGroup();
                audioGroup.setMode(AudioGroup.MODE_ECHO_SUPPRESSION);
                localip = getLocalAddress().toString();


                audioStream = new AudioStream(getLocalAddress());
                locolport.append(String.valueOf(audioStream.getLocalPort()));
                audioStream.setCodec(AudioCodec.PCMU);
                audioStream.setMode(RtpStream.MODE_NORMAL);

                //Toast.makeText(MainActivity.this, "line = 10", Toast.LENGTH_SHORT).show();
            } catch (SocketException se) {
                Toast.makeText(MainActivity.this, se.getMessage(), Toast.LENGTH_LONG).show();
            } catch (Exception e) {
                Toast.makeText(MainActivity.this, "line = " + line + e.getMessage() + "\n" + localip, Toast.LENGTH_LONG).show();
                Log.e("-------", e.toString());
                e.printStackTrace();
            }
        }else{
            Toast.makeText(MainActivity.this, "permissions denied rizi", Toast.LENGTH_SHORT).show();
        }
    }
    public void call(View view)
    {
        try {
            //Toast.makeText(MainActivity.this, remote_ip_editText.getText().toString(), Toast.LENGTH_SHORT).show();
            InetAddress remoteIp = InetAddress.getByName(remote_ip_editText.getText().toString());
            Toast.makeText(MainActivity.this, remote_port_editText.getText().toString(), Toast.LENGTH_SHORT).show();
            Integer remotePort= Integer.parseInt(remote_port_editText.getText().toString());
            audioStream.associate(remoteIp, remotePort);
            audioStream.join(audioGroup);
            Toast.makeText(MainActivity.this, "call Success", Toast.LENGTH_SHORT).show();
        }
        catch (UnknownHostException ex){
            Toast.makeText(MainActivity.this, "Unkown host Exception "+ ex.getMessage(), Toast.LENGTH_SHORT).show();
        }
        catch (Exception e) {
            Toast.makeText(MainActivity.this, "Exception "+ e, Toast.LENGTH_SHORT).show();
        }

    }
    public InetAddress getLocalAddress()
    {
        InetAddress localAddress;
        try {
            for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
                NetworkInterface networkInterface = en.nextElement();
                for (Enumeration<InetAddress> enumIpAddr = networkInterface.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
                    InetAddress ip = enumIpAddr.nextElement();
                    if (!ip.isLoopbackAddress()) {
                        if (ip.isSiteLocalAddress()) {
                            return ip;
                        }
                    }
                }
            }
        }
        catch (Exception e)
        {
            Toast.makeText(MainActivity.this, "Exception at get local Address"+e.getMessage(), Toast.LENGTH_SHORT).show();
        }
        return null;
    }


    public  void verifyPermissions(Activity activity) {
        // Check if we have write permission
        int permission1= ActivityCompat.checkSelfPermission(activity, Manifest.permission.MODIFY_AUDIO_SETTINGS);
        int permission2= ActivityCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO);
        int permission3= ActivityCompat.checkSelfPermission(activity, Manifest.permission.INTERNET);



        if (permission1 != PackageManager.PERMISSION_GRANTED || permission2 != PackageManager.PERMISSION_GRANTED || permission3 != PackageManager.PERMISSION_GRANTED ) {
            // We don't have permission so prompt the user
            ActivityCompat.requestPermissions(
                    activity,
                    PERMISSIONS,
                    REQUEST_EXTERNAL_STORAGE
            );
        }else{
            flag=1;
        }
    }

}

这是桌面应用程序的代码。我在桌面应用程序发送器类和接收器类中使用2个类。我在main方法中使用这些类作为线程。

接收者类

package rtpstreamdesktop;




import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.Player;



public class SimpleVoiceReceiver implements Runnable
{

    /**
     * @param args
     */
   public void run(){




            // ip and port declaration for rtp session
        String url = "rtp://192.168.8.106:60002/audio/16";

        MediaLocator mrl = new MediaLocator(url);

        // Create a player for this rtp session
        Player player = null;
        try
        {
            player = Manager.createPlayer(mrl);
        } catch (Exception e)
        {
                    System.out.println("player creation exception");
                }

        if (player != null)
        {
            System.out.println("Player created: ");
            player.realize();
            // wait for realizing (construction of media player)
            while (player.getState() != Player.Realized)
            {
                try
                {
                    Thread.sleep(10);
                } catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
            System.out.println("Starting player: ");
            player.start();
        } else
        {
            System.err.println("Player doesn't created: ");
            System.exit(-1);
        }


    }

}

发射器类

package rtpstreamdesktop;



import java.util.Vector;
import javax.media.CaptureDeviceInfo;
import javax.media.CaptureDeviceManager;
import javax.media.DataSink;
import javax.media.Format;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NotRealizedError;
import javax.media.Processor;
import javax.media.control.FormatControl;
import javax.media.control.TrackControl;
import javax.media.format.AudioFormat;
import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.DataSource;


/**
 * 
 * @author Abdul Rab
 *
 */
public class SimpleVoiceTransmiter implements Runnable
{

    /**
     * @param args
     */
    public void run()
    {
                CaptureDeviceInfo di = null;
        Format format;
        format = new AudioFormat(AudioFormat.ULAW_RTP, 8000, 8, 1);
            // First find a capture device that will capture linear audio
            // data at 8bit 8Khz
        AudioFormat captureFormat = new AudioFormat(AudioFormat.LINEAR, 8000, 16, 1);

        Vector devices = CaptureDeviceManager.getDeviceList(captureFormat);



        if (devices.size() > 0)
            {
                di = (CaptureDeviceInfo) devices.elementAt(0);
            } else
            {
                System.err.println("No capture devices");
                // exit if we could not find the relevant capturedevice.
                System.exit(-1);
            }


        // Create a processor for this capturedevice & exit if we
        // cannot create it
        Processor processor = null;
        try
        {
                    processor = Manager.createProcessor(di.getLocator());
        } catch (Exception e)
        {
                    System.out.println("Procesor Exception: ");
                }

        // configure the processor
        processor.configure();

        while (processor.getState() != Processor.Configured)
        {
            try
            {
                Thread.sleep(100);
            } catch (InterruptedException e)
            {
                 System.out.println("interupted processor exception: ");
            }
        }

        processor.setContentDescriptor(new ContentDescriptor(ContentDescriptor.RAW_RTP));

        TrackControl track[] = processor.getTrackControls();

        boolean encodingOk = false;

        // Go through the tracks and try to program one of them to
        // output gsm data.

        for (int i = 0; i < track.length; i++)
        {
            if (!encodingOk && track[i] instanceof FormatControl)
            {
                if (((FormatControl) track[i]).setFormat(format) == null)
                {

                    track[i].setEnabled(false);
                } else
                {
                    encodingOk = true;
                }
            } else
            {
                // we could not set this track to gsm, so disable it
                track[i].setEnabled(false);
            }
        }

        // At this point, we have determined where we can send out
        // gsm data or not.
        // realize the processor
        if (encodingOk)
        {
            if (!new net.sf.fmj.ejmf.toolkit.util.StateWaiter(processor).blockingRealize())
            {
                System.err.println("Failed to realize");
                return;
            }

            // get the output datasource of the processor and exit
            // if we fail
            DataSource ds = null;

            try
            {
                ds = processor.getDataOutput();
            } catch (NotRealizedError e)
            {
                e.printStackTrace();
                System.exit(-1);
            }

            // hand this datasource to manager for creating an RTP
            // datasink our RTP datasink will multicast the audio
            try
            {
                String url = "rtp://192.168.8.102:60010/audio/16";

                MediaLocator m = new MediaLocator(url);

                DataSink d = Manager.createDataSink(ds, m);
                d.open();
                d.start();

                System.out.println("Starting processor");
                processor.start();
                Thread.sleep(30000);
            } catch (Exception e)
            {
                            System.out.println("RTP connection exception: ");
                System.exit(-1);
            }
        }

    }

}

主类

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package rtpstreamdesktop;



/**
 *
 * @author Rizwan
 */
public class RtpStreamDesktop {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
         new Thread(new SimpleVoiceReceiver()).start();
         new Thread(new SimpleVoiceTransmiter()).start();
    }

}

1 个答案:

答案 0 :(得分:0)

我不会不喜欢你的代码如何在一个方向上工作,因为你在Android端使用(正确)Android.net.rtp包(比你发送/接收Voip数据包),而它似乎你在PC端没有任何Voip模块;在您的代码中,您尝试使用MediaLocator播放Voip数据包,但Voip数据包不是媒体文件(如mp3)。

在我看来,解决方案可能是在PC端,导入一个Voip Java模块(有一些开源类似于&#39; pjsip&#39;)但你必须适应和研究它。这部分既费时又不容易,因为你必须了解voip的工作原理等等......

Ciao,Fausto