java - 使用 RTP 在 JMF 中实现播放器

标签 java audio stream rtp jmf

我遇到了一个问题,我在一周的大部分时间里都在努力解决这个问题,并且尝试了至少 10 种不同的实现方式,但似乎都失败了。一定有我不明白的地方。

我正在使用 jmf 通过 rtp 传输音频。问题是客户端播放器永远不会意识到,因此,代码块,什么也玩不了。

Transmitter 的代码如下:

import java.io.File;
import java.io.IOException;
import javax.media.DataSink;
import javax.media.Format;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoProcessorException;
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;

public class RTPTransmitter
{

/**
 * @param args
 */
public static void main(String[] args)
{
    File f = new File("streamtest.wav");

    Format format;

    format = new AudioFormat(AudioFormat.ULAW_RTP, 8000, 8, 1);

    Processor processor = null;
    try
    {
        processor = Manager.createProcessor(f.toURI().toURL());
    } catch (IOException e)
    {
        e.printStackTrace();
        System.exit(-1);
    } catch (NoProcessorException e)
    {
        e.printStackTrace();
        System.exit(-1);
    }

    // configure the processor
    processor.configure();

    while (processor.getState() != Processor.Configured)
    {
        try
        {
            Thread.sleep(100);
        } catch (InterruptedException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    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);
        }
    }

    //realize the processor
    processor.realize();
    while(processor.getState() != processor.Realized){
        try
        {
            Thread.sleep(100);
        } catch (InterruptedException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    // At this point, we have determined where we can send out
    // gsm data or not.
    if (encodingOk)
    {       
        // 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://127.0.0.1:8000/audio/1";

            MediaLocator m = new MediaLocator(url);

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

            System.out.println("Starting processor");
            processor.start();
            System.out.println("Processor Started");
            Thread.sleep(30000);
        } catch (Exception e)
        {
            e.printStackTrace();
            System.exit(-1);
        }
    }

}

}

接收器的代码是:

import java.io.IOException;
import java.net.MalformedURLException;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoPlayerException;
import javax.media.Player;

public class RTPReceiver
{

/**
 * @param args
 */
public static void main(String[] args)
{
    String url = "rtp://127.0.0.1:8000/audio/1";

    MediaLocator mrl = new MediaLocator(url);

    // Create a player for this rtp session
    Player player = null;
    try
    {
        player = Manager.createPlayer(mrl);
    } catch (NoPlayerException e)
    {
        e.printStackTrace();
        System.exit(-1);
    } catch (MalformedURLException e)
    {
        e.printStackTrace();
        System.exit(-1);
    } catch (IOException e)
    {
        e.printStackTrace();
        System.exit(-1);
    }

    if (player != null)
    {
        System.out.println("Player created.");
        player.realize();
        // wait for realizing
        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 won't create.");
        System.exit(-1);
    }

    System.out.println("Exiting.");
}

}

发射器启动正常,一切都开始了,一切似乎都正常。所以我启动接收器,它只是在

while (player.getState() != Player.Realized)

让我非常沮丧的是,这是一个简单的测试用例,而这些文件直接改编自示例。此外,它们尽可能简单,但它们似乎仍然不起作用。

任何帮助将不胜感激! 谢谢!

最佳答案

嘿,我能理解这种挫败感。我自己也有类似的问题。无论如何,我有几乎相同的发射器,但在接收器中,我使用 ControlListener 来监听播放器何时实现。

public AudioRTPRecv() {
    MediaLocator mrl= new MediaLocator("rtp://192.168.1.100:49151/audio/1");

    // Create a player for this rtp session
    try {
        player = Manager.createPlayer(mrl);
    } catch (Exception e) {
        System.err.println("Error:" + e);
        return;
    }

    if (player != null) {
        player.addControllerListener(this);
        player.realize();
    }
}

public synchronized void controllerUpdate(ControllerEvent ce) {
    System.out.println(ce);
    if(ce instanceof TransitionEvent) {
        if (((TransitionEvent)ce).getCurrentState() == Processor.Realized) {
            player.start();
            System.out.println("starting player now");
        }
    }
}

这有一个额外的好处,即 controllerUpdate 方法中的打印语句让您了解播放器正在发生的事情。

关于java - 使用 RTP 在 JMF 中实现播放器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7705524/

相关文章:

bash - 使用 mkfifo 和传输流,这可能吗?

java - 在 JAVA 中使用配置 - 最佳实践

java - Log4J:无法在 FileAppender 处使用 bufferedIO = true 更改 bufferSize

c# - 实时复制缓冲区数据

audio - FMOD中的setFrequency不能令人满意地工作

Ruby,合并惰性序列

父类(super class)的Java同步私有(private)方法

java - Spring @ModelAttribute 将格式化数字转换为 Double

iphone - 您如何使用 Objective-C 让声音文件自动播放到 iOS 应用程序并循环播放?

SQLite VFS 使用流