这是带有症状的代码:

      /*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.zove.xuggleraudio;

import com.xuggle.xuggler.IAudioSamples;
import com.xuggle.xuggler.IContainer;
import com.xuggle.xuggler.IStream;
import com.xuggle.xuggler.IStreamCoder;
import com.xuggle.xuggler.ICodec;
import com.xuggle.xuggler.IPacket;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.Line;
import javax.sound.sampled.LineUnavailableException;

import javax.sound.sampled.SourceDataLine;

/**
 * Class that represents an audio player with the expected
 * controls (start, stop, pause, resume).
 * @author Mciavilli
 */
public class Audio
{
    //The name of the file to be played
    private final String filename;
    //Our connection to the mixer
    private final SourceDataLine mLine;
    //The index of the audio stream inside the file
    private final int audioId;
    //Xuggler media container
    private final IContainer container;
    //The stream decoder
    private final IStreamCoder streamCoder;

    /*
     * Constructor that takes a String argument
     */
    public Audio(String filename)
    {
        this.filename = filename;
        //Create Xuggler container object
        this.container = IContainer.make();
        //Open the container
        if(container.open(filename, IContainer.Type.READ, null) < 0)
            throw new IllegalArgumentException("Invalid file name: " + this.filename);
        //find the audio stream within contained streams
        this.audioId = getAudioId(container);
        //get the audio stream
        IStream stream = container.getStream(audioId);
        //get the stream decoder
        this.streamCoder = stream.getStreamCoder();
        //open the stream decoder
        if (this.streamCoder.open() < 0)
            throw new RuntimeException("could not open audio decoder for container: "
              + filename);
        //Get a pipe to the sound mixer
        this.mLine = readySoundSystem(streamCoder);
    }

    private int getAudioId(IContainer container)
    {
        //see how many streams are there
        int numStreams = container.getNumStreams();
        int audioId = -1;
        for(int i = 0; i < numStreams ; i++)
        {
            IStream stream = container.getStream(i);
            IStreamCoder streamCoder = stream.getStreamCoder();
            if(streamCoder.getCodecType() == ICodec.Type.CODEC_TYPE_AUDIO)
                audioId = i;
                break;
        }//end for statement
        //No audio stream found
        if(audioId == -1)
            throw new RuntimeException("Failed to find an audio stream in:" +
                    this.filename);

        return audioId;
    }//end method getAudioId

    private SourceDataLine readySoundSystem(IStreamCoder aAudioCoder)
    {
        AudioFormat audioFormat = new AudioFormat(aAudioCoder.getSampleRate(),
            (int)IAudioSamples.findSampleBitDepth(aAudioCoder.getSampleFormat()),
            aAudioCoder.getChannels(),
            true, /* xuggler defaults to signed 16 bit samples */
            false);
        DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
        try
        {
          SourceDataLine mLine = (SourceDataLine) AudioSystem.getLine(info);
          /**
           * if that succeeded, try opening the line.
           */
          mLine.open(audioFormat);
          /**
           * And if that succeed, start the line.
           */
          mLine.start();
        }
        catch (LineUnavailableException e)
        {
          throw new RuntimeException("could not open audio line");
        }
        return mLine;
      }//end method readySoundSystem
    /*
     * starts playing the file.
     * returns true if successful.
     * should be called only once per Audio object
     */
    public boolean start()
    {
        if(!mLine.isActive())
        {
            IPacket packet = IPacket.make();
            while(container.readNextPacket(packet) >= 0)
            {
              /*
               * Now we have a packet, let's see if it belongs to our audio stream
               */
              if (packet.getStreamIndex() == this.audioId)
              {
                /*
                 * We allocate a set of samples with the same number of channels as the
                 * coder tells us is in this buffer.
                 *
                 * We also pass in a buffer size (1024 in our example), although Xuggler
                 * will probably allocate more space than just the 1024 (it's not important why).
                 */
                IAudioSamples samples = IAudioSamples.make(1024, this.streamCoder.getChannels());

                /*
                 * A packet can actually contain multiple sets of samples (or frames of samples
                 * in audio-decoding speak).  So, we may need to call decode audio multiple
                 * times at different offsets in the packet's data.  We capture that here.
                 */
                int offset = 0;

                /*
                 * Keep going until we've processed all data
                 */
                while(offset < packet.getSize())
                {
                  int bytesDecoded = this.streamCoder.decodeAudio(samples, packet, offset);
                  if (bytesDecoded < 0)
                    throw new RuntimeException("got error decoding audio in: " + filename);
                  offset += bytesDecoded;
                  /*
                   * Some decoder will consume data in a packet, but will not be able to construct
                   * a full set of samples yet.  Therefore you should always check if you
                   * got a complete set of samples from the decoder
                   */
                  if (samples.isComplete())
                  {
                    playSound(samples);
                  }
                }//end inner while block
              }//end inner if block
              else
              {
                /*
                 * This packet isn't part of our audio stream, so we just silently drop it.
                 */
                do {} while(false);
              }//end else block
            }//end outer while block
            //success!
            return true;
     }//end outer if block
        //The sound is already playing
        return false;
    }//end method start

    private void playSound(IAudioSamples aSamples)
      {
        /**
         * We're just going to dump all the samples into the line.
         */
        byte[] rawBytes = aSamples.getData().getByteArray(0, aSamples.getSize());
        this.mLine.write(rawBytes, 0, aSamples.getSize());
      }//end method playJavaSound

    /*
     * stops the playback
     * returns true if suucessful
     */
    public boolean stop()
    {
        if(mLine.isActive())
        {
            this.mLine.stop();
            return true;
        }
        return false;
    }

    public static void main(String args[]) throws InterruptedException
    {
        if(args.length != 1)
            throw new IllegalArgumentException("illegal arguments passed");
        Audio audio = new Audio(args[0]);
        audio.start();
        Thread.sleep(10 * 1000);
        audio.stop();
    }

}//end class Audio

导致问题的行是第104行:
mLine.start();

当我检查调试器时,在执行此行之前,mLine对象(SourceDataLine对象)可以正常运行,这将导致mLine等于“null”。

我认为这个问题与here相同。

我还尝试使用Clip而不是SourceDataLine,最终出现了同样的问题。

有趣的是,此问题不会在original Xuggler program中发生,并且调用start()并不会产生不良影响。

最佳答案

您同时具有成员变量mLine和局部变量mLine。只有后者曾经被分配过。当它超出范围时,在调试器中看到的是成员变量,该变量仍为null。

关于java - SourceDataLine.start()使对象为空,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12503719/

10-10 21:46