Joal learning notes Class 8 oggvorbis format stream

Source: Internet
Author: User

Joal Study Notes

 

If I compare the number of errors in the previous instance code to Mao Yu, I have made this course a big storm ......


As the original author of this course did not provide a complete piece of code or the implementation of the decoder, I am here to paste the tested code that I have called.

First, paste a picture so that you can understand the entire implementation system:

It can be seen that I did not select the J-oggapi provided by the j-ogg.de of the tutorial recommendations, this German site does not have an example of the explanation, just provide an API documentation, I have written some test code referring to this document and found that an array out-of-bounds error is reported internally. It is estimated that this API has a bug.

 

In addition to this, another reason for choosing Java sound API as the decoder's core is that there are mature SPI components in MP3, Ogg, and other formats. We do not need to explicitly call which decoder to use, mongoound will automatically find the service that supports Decoding in the system, so that a set of APIs can be used for different formats of files.

 

Before you finally paste the code, first give the source of the dependency item. This time there are many dependencies:

Jlayer: http://www.javazoom.net/javalayer/javalayer.html

Mp3spi: http://www.javazoom.net/mp3spi/mp3spi.html

Oggvorbispi: http://www.javazoom.net/vorbisspi/vorbisspi.html

Jorbis: http://www.jcraft.com/jorbis/, which is the dependency of oggspi

Project:

Jcraft resources are not compiled after being downloaded. You need to add them to the project by yourself. Please note that.


Source code:

Main. Java:

package com.thrblock.openal;import com.jogamp.openal.ALFactory;import com.jogamp.openal.util.ALut;public class Main {public static void main(String[] args) {ALut.alutInit();OggVorbisPlayer player = new OggVorbisPlayer(ALFactory.getAL(),"./oggData/ThorVariation.ogg");//OggVorbisPlayer player = new OggVorbisPlayer(ALFactory.getAL(),"./mp3Data/009.mp3");//OggVorbisPlayer player = new OggVorbisPlayer(ALFactory.getAL(),"./wavData/0201.wav");player.open();player.playstream();player.release();}}


Oggdecoder. Java:

package com.thrblock.openal;import java.io.File;import java.io.IOException;import javax.sound.sampled.AudioFormat;import javax.sound.sampled.AudioInputStream;import javax.sound.sampled.AudioSystem;import javax.sound.sampled.UnsupportedAudioFileException;public class OggDecoder {private boolean inited = false;private AudioFormat baseFormat, decodedFormat;private AudioInputStream audioInputStream, decodedAudioInputStream;public OggDecoder(String fileName) {try {File file = new File(fileName);audioInputStream = AudioSystem.getAudioInputStream(file);baseFormat = audioInputStream.getFormat();decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,baseFormat.getSampleRate(), 16, baseFormat.getChannels(),baseFormat.getChannels() * 2, baseFormat.getSampleRate(),false);decodedAudioInputStream = AudioSystem.getAudioInputStream(decodedFormat, audioInputStream);inited = true;} catch (IOException | UnsupportedAudioFileException e) {if (e instanceof UnsupportedAudioFileException) {System.out.println("UnSupport File!");}System.out.println("Error in load Ogg File");}}public boolean initialize() {return inited;}public int numChannels() {return decodedFormat.getChannels();}public float sampleRate() {return decodedFormat.getSampleRate();}public int read(byte[] pcm) throws IOException {return decodedAudioInputStream.read(pcm, 0, pcm.length);}public void dump() {System.out.println("dump!");}}


Oggvorbisplayer. Java:
Package COM. thrblock. openal; import Java. NIO. bytebuffer; import Java. util. arrays; import COM. jogamp. openal. al; public class oggvorbisplayer {// The block size is the amount of data we want to read from the stream each time. Private Static int buffer_size = 4096*8; // Number of buffers to be used in the audio pipeline Private Static int num_buffers = 4; // buffer for storing sound data. two private int [] buffers = new int [num_buffers] by default (front buffer/back buffer); // the sound source private int [] source = new int [1]; static float [] sourcepos = {0.0f, 0.0f, 0.0f}; static float [] sourcevel = {0.0f, 0.0f, 0.0f}; static float [] sourcedir = {0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f}; static float [] listenerp OS = {0.0f, 0.0f, 0.0f}; static float [] listenervel = {0.0f, 0.0f, 0.0f}; // decoder private oggdecoder; private int format; private float rate; private al; private string URL; Public oggvorbisplayer (Al, string URL) {This. al = Al; this. url = URL;}/*** initialize and play the main loop of the stream */Public Boolean playstream () {If (! Open () return false; // oggdecoder. Dump (); If (! Playback () return false; system. Out. println ("playing! "); While (Update () {If (playing () {try {thread. sleep (10);} catch (interruptedexception e) {} continue;} // system. out. println ("not playing! "); If (! Playback () return false;} return true;}/*** open the Ogg stream and initialize openal */Public Boolean open () based on the stream attributes () {oggdecoder = new oggdecoder (URL); If (! Oggdecoder. initialize () {system. err. println ("error Initializing stream... "); Return false;} If (oggdecoder. numchannels () = 1) {format = Al. al_format_mono16;} else {format = Al. al_format_stereo16;} rate = oggdecoder. samplerate (); Al. algenbuffers (num_buffers, buffers, 0); check ("open_1"); Al. algensources (1, source, 0); check ("open_2"); Al. alsourcefv (source [0], Al. al_position, sourcepos, 0); Al. alsourcefv (so Urce [0], Al. al_velocity, sourcevel, 0); Al. alsourcefv (source [0], Al. al_direction, sourcedir, 0); Al. alsourcef (source [0], Al. al_roloff_factor, 0.0f); Al. alsourcei (source [0], Al. al_source_relative, Al. al_true); Return true;}/*** process of clearing openal */Public void release () {Al. alsourcestop (source [0]); empty (); For (INT I = 0; I <num_buffers; I ++) {Al. aldeletesources (I, source, 0); check ("release_1") ;}}/*** play og G stream */private Boolean playback () {If (playing () return true; For (INT I = 0; I <num_buffers; I ++) {If (! Stream (buffers [I]) return false;} Check ("playback_1"); Al. alsourcequeuebuffers (source [0], num_buffers, buffers, 0); check ("playback_2"); Al. alsourceplay (source [0]); check ("playback_3"); Return true;}/*** checks whether the player is currently playing */private Boolean playing () {int [] State = new int [1]; Al. algetsourcei (source [0], Al. al_source_state, state, 0); Return (State [0] = Al. al_playing);}/*** if needed, read the next part of the stream into the buffer */private Boolean Update () {int [] processed = new int [1]; Boolean active = true; Al. algetsourcei (source [0], Al. al_buffers_processed, processed, 0); While (processed [0]> 0) {int [] buffer = new int [1]; Al. alsourceunqueuebuffers (source [0], 1, buffer, 0); check ("update_1"); active = stream (buffer [0]); Al. alsourcequeuebuffers (source [0], 1, buffer, 0); check ("update_2"); processed [0] --;} return active ;} /*** re-load the buffer (read into the next block) */B Yte [] PCM = new byte [buffer_size]; bytebuffer DATA = bytebuffer. wrap (PCM, 0, PCM. length); Private Boolean stream (INT buffer) {int size = 0; try {arrays. fill (PCM, (byte) 0); While (size = oggdecoder. read (PCM) = 0); If (size <0) {return false ;}} catch (exception e) {e. printstacktrace (); Return false;} If (size> 0) {Al. albufferdata (buffer, format, Data, size, (INT) rate);} Check ("stream_1" + buffer); Return t Rue;}/*** clear queue */private void empty () {int [] queued = new int [1]; Al. algetsourcei (source [0], Al. al_buffers_queued, queued, 0); While (queued [0]> 0) {int [] buffer = new int [1]; Al. alsourceunqueuebuffers (source [0], 1, buffer, 0); check ("empty_1"); queued [0] --;} oggdecoder = NULL;} private void check (string flag) {int TMP; If (TMP = Al. algeterror ())! = Al. al_no_error) {system. out. println (getalerrorstring (TMP) + ", error," + flag) ;}} private string getalerrorstring (int err) {Switch (ERR) {Case Al. al_no_error: Return "al_no_error"; Case Al. al_invalid_name: Return "al_invalid_name"; Case Al. al_invalid_enum: Return "al_invalid_enum"; Case Al. al_invalid_value: Return "al_invalid_value"; Case Al. al_invalid_operation: Return "al_invalid_operation"; Case Al. al_out_of_memory: Return "al_out_of_memory"; default: return NULL ;}}}

Notes:

 

First of all, I don't know if it is because of the problem caused by the decoding method of mongoound + SPI. The Ogg stream sometimes reads 0 bytes, and the file is not over yet. After research, it is found that this value is valid (writing the sourcedataline of javax can play the Ogg audio correctly). Therefore, when filling the buffer zone, you must wait until the data is filled in, 0 is invalid in openal. Here, you can refer to the changes in the above stream method relative to the original article.


Secondly, after using Al. albufferdata, the byte [] group of data in JVM has been filled to the openal level. Therefore, its array can be reused without the need for new data each time.


Finally, I want to talk about the update call frequency.

Because we need to manage the Buffer Queue, we have to separate a thread to do these tasks, that is, the update Method and Its loop structure in our article. If there is no accident in the original article, update will be called at the maximum possible frequency, which will directly occupy a CPU core or a line that supports hyper-threading CPU, the advantage is that the fastest response to the playback control (such as pause, stop, and continue.

At this point, if a blocking delay is added, for example, sleep (1), the CPU usage will be greatly reduced, and 1 ms is enough for the CPU. However, blocking will affect the control response time, which is limited by blocking time.

The author believes that in most cases, the response to the control demand for playing music is not very high. For example, after the command is issued to stop playing, the immediate stop and 1 ms delay are not very different for people, therefore, proper blocking is necessary.

If the blocking time is too long, it will lead to another situation where the buffer zone data is played completely without being filled in. At this time, the concert is obviously choppy.

 

Therefore, the congestion time must be determined after factors such as the buffer size, response time requirement, and CPU consumption are weighed.




Joal learning notes Class 8 oggvorbis format stream

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.