From 1db6779decefff9f4bbded99003fe4b63eae6ae7 Mon Sep 17 00:00:00 2001 From: denny Date: Fri, 22 Jan 2016 16:35:18 -0500 Subject: [PATCH] Audio outputs - added exception handler to catch any errors that occur while the buffer processor thread is running. Added check for 0 space available in data line buffers to avoid trying to write a zero-length audio chunk to the data line. Added thread sleep for 100 milliseconds when we detect that the data line buffer is full, to allow time for the data line to drain before we check it again. Hopefully this should minimize the chattering during playback when the code was repeatedly hitting the available() method to check for space availability. --- src/audio/output/MonoAudioOutput.java | 156 +++++++++++++----------- src/audio/output/StereoAudioOutput.java | 118 ++++++++++-------- 2 files changed, 152 insertions(+), 122 deletions(-) diff --git a/src/audio/output/MonoAudioOutput.java b/src/audio/output/MonoAudioOutput.java index 13aa4ea3..b577f241 100644 --- a/src/audio/output/MonoAudioOutput.java +++ b/src/audio/output/MonoAudioOutput.java @@ -24,7 +24,6 @@ import audio.AudioEvent; import audio.AudioFormats; import audio.AudioPacket; import audio.AudioPacket.Type; -import audio.output.StereoAudioOutput.QueueProcessor; import controller.NamingThreadFactory; /** @@ -144,96 +143,115 @@ public class MonoAudioOutput extends AudioOutput { private AtomicBoolean mProcessing = new AtomicBoolean(); - public QueueProcessor() - { - } - @Override public void run() { - /* The mProcessing flag ensures that only one instance of the - * processor can run at any given time */ - if( mProcessing.compareAndSet( false, true ) ) + try { - List packets = new ArrayList(); - - mBuffer.drainTo( packets ); - - if( packets.size() > 0 ) + /* The mProcessing flag ensures that only one instance of the + * processor can run at any given time */ + if( mProcessing.compareAndSet( false, true ) ) { - broadcast( mAudioContinuationEvent ); + List packets = new ArrayList(); - for( AudioPacket packet: packets ) + mBuffer.drainTo( packets ); + + if( packets.size() > 0 ) { - if( mCanProcessAudio ) + broadcast( mAudioContinuationEvent ); + + for( AudioPacket packet: packets ) { - if( isSquelched() ) + if( mCanProcessAudio ) { - checkStop(); - } - else if( packet.getType() == Type.AUDIO ) - { - float[] samples = packet.getAudioBuffer().getSamples(); - - /* Little-endian byte buffer */ - ByteBuffer buffer = - ByteBuffer.allocate( samples.length * 2 ) - .order( ByteOrder.LITTLE_ENDIAN ); - - ShortBuffer shortBuffer = buffer.asShortBuffer(); - - for( float sample: samples ) + if( isSquelched() ) { - shortBuffer.put( (short)( sample * Short.MAX_VALUE ) ); + checkStop(); } - - if( mOutput.available() >= buffer.array().length ) + else if( packet.getType() == Type.AUDIO ) { - mOutput.write( buffer.array(), 0, - buffer.array().length ); - - checkStart(); - } - else - { - int wrote = 0; - - int toWrite = buffer.array().length; + float[] samples = packet.getAudioBuffer().getSamples(); - while( toWrite > 0 ) - { - int available = mOutput.available(); + /* Little-endian byte buffer */ + ByteBuffer buffer = + ByteBuffer.allocate( samples.length * 2 ) + .order( ByteOrder.LITTLE_ENDIAN ); + + ShortBuffer shortBuffer = buffer.asShortBuffer(); - if( available < toWrite ) - { - wrote += mOutput.write( buffer.array(), wrote, - available ); - } - else - { - wrote += mOutput.write( buffer.array(), wrote, - toWrite ); - } + for( float sample: samples ) + { + shortBuffer.put( (short)( sample * Short.MAX_VALUE ) ); + } + + if( mOutput.available() >= buffer.array().length ) + { + mOutput.write( buffer.array(), 0, + buffer.array().length ); checkStart(); - - toWrite = buffer.array().length - wrote; } - } - - broadcast( packet.getAudioMetadata() ); + else + { + int wrote = 0; - mLastActivity = System.currentTimeMillis(); + int toWrite = buffer.array().length; + + while( toWrite > 0 ) + { + int available = mOutput.available(); + + if( available < toWrite ) + { + if( available > 0 ) + { + wrote += mOutput.write( buffer.array(), + wrote, available ); + + checkStart(); + } + else + { + try + { + Thread.sleep( 100 ); + } + catch ( InterruptedException e ) + { + mLog.debug( "Mono Audio Output - interrupted while sleeping awaiting buffer drain" ); + } + } + } + else + { + wrote += mOutput.write( buffer.array(), wrote, + toWrite ); + + checkStart(); + } + + toWrite = buffer.array().length - wrote; + } + } + + broadcast( packet.getAudioMetadata() ); + + mLastActivity = System.currentTimeMillis(); + } } } } + else + { + checkStop(); + } + + mProcessing.set( false ); } - else - { - checkStop(); - } - - mProcessing.set( false ); + } + catch( Exception e ) + { + mLog.error( "Error while processing audio buffers", e ); } } diff --git a/src/audio/output/StereoAudioOutput.java b/src/audio/output/StereoAudioOutput.java index e03b1b7d..b9e3ebc7 100644 --- a/src/audio/output/StereoAudioOutput.java +++ b/src/audio/output/StereoAudioOutput.java @@ -177,78 +177,90 @@ public class StereoAudioOutput extends AudioOutput @Override public void run() { - /* The mProcessing flag ensures that only one instance of the - * processor can run at any given time */ - if( mProcessing.compareAndSet( false, true ) ) + try { - List packets = new ArrayList(); - - mBuffer.drainTo( packets ); - - if( packets.size() > 0 ) + /* The mProcessing flag ensures that only one instance of the + * processor can run at any given time */ + if( mProcessing.compareAndSet( false, true ) ) { - broadcast( mAudioContinuationEvent ); + List packets = new ArrayList(); - for( AudioPacket packet: packets ) + mBuffer.drainTo( packets ); + + if( packets.size() > 0 ) { - if( mCanProcessAudio ) + broadcast( mAudioContinuationEvent ); + + for( AudioPacket packet: packets ) { - if( isSquelched() ) + if( mCanProcessAudio ) { - checkStop(); - } - else if( packet.getType() == Type.AUDIO ) - { - ByteBuffer buffer = convert( - packet.getAudioBuffer().getSamples() ); - - if( mOutput.available() >= buffer.array().length ) + if( isSquelched() ) { - mOutput.write( buffer.array(), 0, - buffer.array().length ); - - checkStart(); + checkStop(); } - else + else if( packet.getType() == Type.AUDIO ) { - int wrote = 0; - - int toWrite = buffer.array().length; + ByteBuffer buffer = convert( + packet.getAudioBuffer().getSamples() ); - while( toWrite > 0 ) + if( mOutput.available() >= buffer.array().length ) { - int available = mOutput.available(); - - if( available < toWrite ) - { - wrote += mOutput.write( buffer.array(), wrote, - available ); - } - else - { - wrote += mOutput.write( buffer.array(), wrote, - toWrite ); - } + mOutput.write( buffer.array(), 0, + buffer.array().length ); checkStart(); - - toWrite = buffer.array().length - wrote; } + else + { + int wrote = 0; + + int toWrite = buffer.array().length; + + while( toWrite > 0 ) + { + int available = mOutput.available(); + + if( available < toWrite ) + { + if( available > 0 ) + { + wrote += mOutput.write( buffer.array(), + wrote, available ); + + checkStart(); + } + } + else + { + wrote += mOutput.write( buffer.array(), wrote, + toWrite ); + + checkStart(); + } + + toWrite = buffer.array().length - wrote; + } + } + + broadcast( packet.getAudioMetadata() ); + + mLastActivity = System.currentTimeMillis(); } - - broadcast( packet.getAudioMetadata() ); - - mLastActivity = System.currentTimeMillis(); } } } + else + { + checkStop(); + } + + mProcessing.set( false ); } - else - { - checkStop(); - } - - mProcessing.set( false ); + } + catch( Exception e ) + { + mLog.error( "Error while processing audio buffers", e ); } }