Issue Encoding And Decoding An Audio Recording To G711 ( Pcmu - Ulaw) Format
Solution 1:
Ok guys, finally I resolved for myself the problem encoding/decoding audio. It's been a annoying task during the last week. The main problem of my code was the encoding was well done but the decoding wasn't so I was working around it and modify these class with the help of other resources and I've created my own encoding/decoding methods (and these are working like a charm!!!).
Other important decision was to change the encoding format. Now I am using alaw, and not anymore ulaw. The only reason why I did this change is because programmatically is easier to implement alaw than ulaw.
Also I had to play a lot with the parameters as a buffers sizes, etc etc.
I will submit my code and I hope that someone of you could save so much time using my references.
privateint port=50005;
privateintsampleRate=8000; //44100;privateintchannelConfig= AudioFormat.CHANNEL_IN_MONO;
privateintaudioFormat= AudioFormat.ENCODING_PCM_16BIT;
intminBufSize= AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
publicvoidstartStreamingEncoding() {
ThreadstreamThread=newThread(newRunnable() {
@Overridepublicvoidrun() {
try {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
DatagramSocketsocket=newDatagramSocket();
byte[] buffer = newbyte[4096];
DatagramPacket packet;
finalInetAddressdestination= InetAddress.getByName(ip_receiver);
recorder = newAudioRecord(MediaRecorder.AudioSource.MIC,sampleRate,channelConfig,audioFormat, minBufSize * 10);
recorder.startRecording();
/////Encoding:CMG711encoder=newCMG711();
byte[] outBuffer = newbyte[4096];
int read, encoded;
FilesdCard= Environment.getExternalStorageDirectory();
FileOutputStreamout=newFileOutputStream( newFile( sdCard ,"audio-bernard.raw" ));
while(status == true) {
//reading data from MIC into buffer
read = recorder.read(buffer, 0, buffer.length);
Log.d(getTag(), "read: "+read );
//Encoding:
encoded = encoder.encode(buffer,0, read, outBuffer);
//putting buffer in the packet
packet = newDatagramPacket (outBuffer, encoded, destination,port);
out.write( outBuffer, 0, encoded );
socket.send(packet);
}
} catch(UnknownHostException e) {
Log.e("VS", "UnknownHostException");
} catch (IOException e) {
e.printStackTrace();
Log.e("VS", "IOException");
}
}
});
streamThread.start();
}
And for the receiver and player class or method:
privateint port=50005;
privateintsampleRate=8000 ;//44100;privateintchannelConfig= AudioFormat.CHANNEL_OUT_MONO;
privateintaudioFormat= AudioFormat.ENCODING_PCM_16BIT;
intminBufSize= AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat);
publicvoidplayerAudioDecodingBernard()
{
Threadthrd=newThread(newRunnable() {
@Overridepublicvoidrun()
{
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
AudioTracktrack=newAudioTrack(AudioManager.STREAM_MUSIC,
sampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, minBufSize * 10,
AudioTrack.MODE_STREAM);
CMG711decoder=newCMG711();
try
{
DatagramSocketsock=newDatagramSocket(port);
byte[] buf = newbyte[4096];
intframe=0;
while(true)
{
DatagramPacketpack=newDatagramPacket(buf, 4096);
sock.receive(pack);
//Decoding: intsize= pack.getLength();
//Log.d( "Player", "Player: "+ size +", "+pack.getLength() + ", "+pack.getOffset() );byte[] byteArray = newbyte[size*2];
decoder.decode(pack.getData(), 0, size, byteArray);
track.write(byteArray, 0, byteArray.length);
if( frame++ > 3 )
track.play();
}
}
catch (SocketException se)
{
Log.e("Error", "SocketException: " + se.toString());
}
catch (IOException ie)
{
Log.e("Error", "IOException" + ie.toString());
}
} // end run
});
thrd.start();
}
And this one is the class o encode/decoding in alaw format:
publicclassCMG711
{
/**decompresstableconstants*/privatestaticshortaLawDecompressTable[] =newshort[]
{ -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, -344, -328, -376,
-360, -280, -264, -312, -296, -472, -456, -504, -488, -408, -392, -440, -424, -88, -72, -120, -104, -24, -8, -56, -40, -216, -200, -248, -232, -152, -136, -184, -168, -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, -688, -656, -752, -720, -560, -528, -624, -592, -944, -912, -1008, -976, -816, -784, -880, -848, 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, 2752, 2624,
3008, 2880, 2240, 2112, 2496, 2368, 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, 344, 328, 376, 360, 280, 264, 312, 296, 472, 456, 504, 488, 408, 392, 440, 424, 88, 72, 120, 104, 24, 8, 56, 40, 216, 200, 248, 232, 152, 136, 184, 168, 1376, 1312, 1504, 1440, 1120,
1056, 1248, 1184, 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, 688, 656, 752, 720, 560, 528, 624, 592, 944, 912, 1008, 976, 816, 784, 880, 848 };privatefinalstaticintcClip=32635;privatestaticbyteaLawCompressTable[] =newbyte[]
{ 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 };publicintencode(byte[] src, intoffset, intlen, byte[] res)
{
intj=offset;intcount=len/2;shortsample=0;for(inti=0;i<count;i++)
{
sample=(short)(((src[j++] &0xff)|(src[j++] )<<8));res[i] =linearToALawSample(sample);
}
returncount;
}
privatebytelinearToALawSample(shortsample)
{
intsign;intexponent;intmantissa;ints;sign=((~sample)>>8)&0x80;if(!(sign==0x80))
{
sample=(short)-sample;
}
if(sample>cClip)
{
sample=cClip;
}
if(sample>=256)
{
exponent=(int)aLawCompressTable[(sample>>8)&0x7F];mantissa=(sample>>(exponent+3))&0x0F;s=(exponent<<4)|mantissa;
}
else
{
s=sample>>4;
}
s^=(sign^0x55);return(byte)s;
}
publicvoiddecode(byte[] src, intoffset, intlen, byte[] res)
{
intj=0;for(inti=0;i<len;i++)
{
shorts=aLawDecompressTable[src[i+offset] &0xff];res[j++] =(byte)s;res[j++] =(byte)(s>>8);
}
}
}
Hope to be useful for someone of you! Thanks anyway for the help received, specially to bonnyz.
Solution 2:
What sampleRate have you tried? Sample-rate (both in playback and recording) is something very important because it involves the whole audio pipeline and only few setup are guarantee to work on every devices (I'm sure of 44100). Also, keep in mind that you cannot specify random sampleRate (like 4000), because they will (or they should) be scaled to the nearest supported sampleRate. Similar considerations are valid also for the buffer size.
My guess is that a wrong setup of the pipeline produces sound artifacts which degenerate after the "compression" step.
What happens if you setup you clients with 44100?
Can you try to query the AudioManager and then test variuous supported sampleRate/buffersize
AudioManageraudioManager= (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
Stringrate= audioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
Stringsize= audioManager.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
Post a Comment for "Issue Encoding And Decoding An Audio Recording To G711 ( Pcmu - Ulaw) Format"