Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何正确地检测、解码和播放广播流?_Java_Audio_Stream_Jlayer - Fatal编程技术网

Java 如何正确地检测、解码和播放广播流?

Java 如何正确地检测、解码和播放广播流?,java,audio,stream,jlayer,Java,Audio,Stream,Jlayer,我目前正在尝试用Java编写一个类似自动存储塔的应用程序,它可以播放任何可能的音频源,但在尝试播放广播流时遇到了一些困难 对于我从JavaZoom使用的播放,只要目标是直接媒体文件或直接媒体流(我可以很好地播放PCM、MP3和OGG),就可以正常播放。但是,我在尝试播放包含媒体前数据(如m3u/pls文件)的广播流时遇到困难(我可以通过事先添加检测来修复),或者当网页位于同一位置且传输的媒体取决于请求类型时,在端口80上传输的数据。在后一种情况下,每当我尝试流媒体时,我都会得到HTML数据 隐藏

我目前正在尝试用Java编写一个类似自动存储塔的应用程序,它可以播放任何可能的音频源,但在尝试播放广播流时遇到了一些困难

对于我从JavaZoom使用的播放,只要目标是直接媒体文件或直接媒体流(我可以很好地播放PCM、MP3和OGG),就可以正常播放。但是,我在尝试播放包含媒体前数据(如m3u/pls文件)的广播流时遇到困难(我可以通过事先添加检测来修复),或者当网页位于同一位置且传输的媒体取决于请求类型时,在端口80上传输的数据。在后一种情况下,每当我尝试流媒体时,我都会得到HTML数据

隐藏在网页后面的流链接示例:
这在VLC中是可以播放的,但是如果你把它放到浏览器或我的应用程序中,你会收到一个HTML文件

是否有:

  • 一个现成的免费解决方案,我可以用它来代替JLayer?最好是开源的,这样我就可以研究它了
  • 可以帮助我自己编写解决方案的教程
  • 或者有人能给我举个例子,说明如何正确地检测/请求媒体流吗
提前谢谢

import java.io.*;
import java.net.*;
import javax.sound.sampled.*;
import javax.sound.midi.*;

/**
 * This class plays sounds streaming from a URL: it does not have to preload
 * the entire sound into memory before playing it. It is a command-line
 * application with no gui. It includes code to convert ULAW and ALAW
 * audio formats to PCM so they can be played. Use the -m command-line option
 * before MIDI files.
 */

public class PlaySoundStream {
    // Create a URL from the command-line argument and pass it to the 
    // right static method depending on the presence of the -m (MIDI) option.
    public static void main(String[  ] args) throws Exception {
        if (args[0].equals("-m")) streamMidiSequence(new URL(args[1]));
        else streamSampledAudio(new URL(args[0]));

        // Exit explicitly.
        // This is needed because the audio system starts background threads.
        System.exit(0);
    }

    /** Read sampled audio data from the specified URL and play it */
    public static void streamSampledAudio(URL url)
        throws IOException, UnsupportedAudioFileException,
               LineUnavailableException
    {
        AudioInputStream ain = null;  // We read audio data from here
        SourceDataLine line = null;   // And write it here.

        try {
            // Get an audio input stream from the URL
            ain=AudioSystem.getAudioInputStream(url);

            // Get information about the format of the stream
            AudioFormat format = ain.getFormat( );
            DataLine.Info info=new DataLine.Info(SourceDataLine.class,format);

            // If the format is not supported directly (i.e. if it is not PCM
            // encoded), then try to transcode it to PCM.
            if (!AudioSystem.isLineSupported(info)) {
                // This is the PCM format we want to transcode to.
                // The parameters here are audio format details that you
                // shouldn't need to understand for casual use.
                AudioFormat pcm =
                    new AudioFormat(format.getSampleRate( ), 16,
                                    format.getChannels( ), true, false);

                // Get a wrapper stream around the input stream that does the
                // transcoding for us.
                ain = AudioSystem.getAudioInputStream(pcm, ain);

                // Update the format and info variables for the transcoded data
                format = ain.getFormat( ); 
                info = new DataLine.Info(SourceDataLine.class, format);
            }

            // Open the line through which we'll play the streaming audio.
            line = (SourceDataLine) AudioSystem.getLine(info);
            line.open(format);  

            // Allocate a buffer for reading from the input stream and writing
            // to the line.  Make it large enough to hold 4k audio frames.
            // Note that the SourceDataLine also has its own internal buffer.
            int framesize = format.getFrameSize( );
            byte[  ] buffer = new byte[4 * 1024 * framesize]; // the buffer
            int numbytes = 0;                               // how many bytes

            // We haven't started the line yet.
            boolean started = false;

            for(;;) {  // We'll exit the loop when we reach the end of stream
                // First, read some bytes from the input stream.
                int bytesread=ain.read(buffer,numbytes,buffer.length-numbytes);
                // If there were no more bytes to read, we're done.
                if (bytesread == -1) break;
                numbytes += bytesread;

                // Now that we've got some audio data to write to the line,
                // start the line, so it will play that data as we write it.
                if (!started) {
                    line.start( );
                    started = true;
                }

                // We must write bytes to the line in an integer multiple of
                // the framesize.  So figure out how many bytes we'll write.
                int bytestowrite = (numbytes/framesize)*framesize;

                // Now write the bytes. The line will buffer them and play
                // them. This call will block until all bytes are written.
                line.write(buffer, 0, bytestowrite);

                // If we didn't have an integer multiple of the frame size, 
                // then copy the remaining bytes to the start of the buffer.
                int remaining = numbytes - bytestowrite;
                if (remaining > 0)
                    System.arraycopy(buffer,bytestowrite,buffer,0,remaining);
                numbytes = remaining;
            }

            // Now block until all buffered sound finishes playing.
            line.drain( );
        }
        finally { // Always relinquish the resources we use
            if (line != null) line.close( );
            if (ain != null) ain.close( );
        }
    }

    // A MIDI protocol constant that isn't defined by javax.sound.midi
    public static final int END_OF_TRACK = 47;

    /* MIDI or RMF data from the specified URL and play it */
    public static void streamMidiSequence(URL url)
        throws IOException, InvalidMidiDataException, MidiUnavailableException
    {
        Sequencer sequencer=null;     // Converts a Sequence to MIDI events
        Synthesizer synthesizer=null; // Plays notes in response to MIDI events

        try {
            // Create, open, and connect a Sequencer and Synthesizer
            // They are closed in the finally block at the end of this method.
            sequencer = MidiSystem.getSequencer( );
            sequencer.open( );  
            synthesizer = MidiSystem.getSynthesizer( );
            synthesizer.open( );
            sequencer.getTransmitter( ).setReceiver(synthesizer.getReceiver( ));

            // Specify the InputStream to stream the sequence from
            sequencer.setSequence(url.openStream( ));  

            // This is an arbitrary object used with wait and notify to 
            // prevent the method from returning before the music finishes
            final Object lock = new Object( );

            // Register a listener to make the method exit when the stream is 
            // done. See Object.wait( ) and Object.notify( )
            sequencer.addMetaEventListener(new MetaEventListener( ) {
                    public void meta(MetaMessage e) {
                        if (e.getType( ) == END_OF_TRACK) {
                            synchronized(lock) { 
                                lock.notify( );
                            }
                        }
                    }
                });

            // Start playing the music
            sequencer.start( );

            // Now block until the listener above notifies us that we're done.
            synchronized(lock) {
                while(sequencer.isRunning( )) {
                    try { lock.wait( ); } catch(InterruptedException e) {  }
                }
            }
        }
        finally {
            // Always relinquish the sequencer, so others can use it.
            if (sequencer != null) sequencer.close( );
            if (synthesizer != null) synthesizer.close( );
        }
    }
}
我在一个处理音频流的项目中使用了这段代码,效果很好

此外,您可以在此处看到类似的示例:

只要阅读《给我一个想法》的javadoc就可以了

getAudioInputStream
还有一个签名:您可以给它一个InputStream而不是URL

因此,请尝试自行获取输入流,并添加所需的标题,以便获取流而不是html内容:

URLConnection uc = url.openConnection();
uc.setRequestProperty("<header name here>", "<header value here>");

InputStream in = uc.getInputStream();

ain=AudioSystem.getAudioInputStream(in);
URLConnection uc=url.openConnection();
uc.setRequestProperty(“,”);
InputStream in=uc.getInputStream();
ain=AudioSystem.getAudioInputStream(in);

希望能有所帮助。

我知道这个答案来得晚,但我遇到了同样的问题:我想播放MP3和AAC音频,还想让用户插入PLS/M3U链接。以下是我所做的:
首先,我尝试使用简单的文件名解析类型:

import de.webradio.enumerations.FileExtension;

import java.net.URL;

public class FileExtensionParser {
    /**
     *Parses a file extension
     * @param filenameUrl the url
     * @return the filename. if filename cannot be determined by file extension, Apache Tika parses by live detection
     */
    public FileExtension parseFileExtension(URL filenameUrl) {
        String filename = filenameUrl.toString();
        if (filename.endsWith(".mp3")) {
            return FileExtension.MP3;
        } else if (filename.endsWith(".m3u") || filename.endsWith(".m3u8")) {
            return FileExtension.M3U;
        } else if (filename.endsWith(".aac")) {
            return FileExtension.AAC;
        } else if(filename.endsWith((".pls"))) {
            return FileExtension.PLS;
        }
        URLTypeParser parser = new URLTypeParser();
        return parser.parseByContentDetection(filenameUrl);
    }
}
如果失败,我将使用Apache Tika进行一种实时检测:

public class URLTypeParser {


    /** This class uses Apache Tika to parse an URL using her content
     *
     * @param url the webstream url
     * @return the detected file encoding: MP3, AAC or unsupported
     */

    public FileExtension parseByContentDetection(URL url) {
        try {
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            InputStream in = connection.getInputStream();
            BodyContentHandler handler = new BodyContentHandler();
            AudioParser parser = new AudioParser();
            Metadata metadata = new Metadata();
            parser.parse(in, handler, metadata);
            return parseMediaType(metadata);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TikaException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        }
        return FileExtension.UNSUPPORTED_TYPE;
    }

    private FileExtension parseMediaType(Metadata metadata) {
        String parsedMediaType = metadata.get("encoding");
        if (parsedMediaType.equalsIgnoreCase("aac")) {
            return FileExtension.AAC;
        } else if (parsedMediaType.equalsIgnoreCase("mpeg1l3")) {
            return FileExtension.MP3;
        }
        return FileExtension.UNSUPPORTED_TYPE;
    }

}
这也将解决HTML问题,因为该方法将返回
FileExtension.UNSUPPORTED
,用于HTML内容。
我将这些类与工厂模式结合在一起,效果很好。现场检测只需约两秒钟


我不认为这会对你有任何帮助,但因为我挣扎了将近三个星期,我想提供一个有效的答案。您可以在github上看到整个项目:

MP3SPI怎么样?有关流媒体示例,请参阅。我添加了一个无法播放的广播流示例。这是关于我当前实现的内容,以及由于JLayer而添加的MP3和OGG流媒体,但我的和你的都无法播放广播流。