title: Issue encoding and decoding an audio recording to G711 ( PCMU - uLaw) format
body: <p>There isn't too much info about apply this codec when we need to streaming audio. Without apply the codec, my code work like a charm establishing a communication between 2 devices but I need encode/decode in that format because I will need streaming with the server and not between two devices (I am testing this code using 2 devices).</p>
  
  <p>I am looking for the chance if anyone of your could see where is the key of my problem. I've tried different configurations of the input parameters. Maybe, the codecs that I am using are wrong (I took them from one project with Apache license.)</p>
  
  <p>This values are set in the recorder-sender as in the player-receiver device:</p>
  
  <pre><code>private int port=50005;
  private int sampleRate = 8000 ;//44100;
  private int channelConfig = AudioFormat.CHANNEL_OUT_MONO;    
  private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;       
  int minBufSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat);
  </code></pre>
  
  <p>Note: CHANNEL_OUT_MONO in the player and CHANNEL_IN_MONO in the recorder item.</p>
  
  <p>And these are my methods:</p>
  
  <pre><code>public void startStreamingEncoding() {
  
      Thread streamThread = new Thread(new Runnable() {
  
          @Override
          public void run() {
              try {
  
                  android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
  
                  DatagramSocket socket = new DatagramSocket();
  
                  short[] buffer = new short[minBufSize];
  
                  DatagramPacket packet;
  
                  final InetAddress destination = InetAddress.getByName(ip_receiver); 
  
                  recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,sampleRate,channelConfig,audioFormat,minBufSize*10);
  
                  recorder.startRecording();
  
                  /////Encoding:
                  Encoder encoder = new G711UCodec();
                  byte[] outBuffer = new byte[minBufSize];
  
                  while(status == true) {
  
                      //reading data from MIC into buffer
                      minBufSize = recorder.read(buffer, 0, buffer.length);
                      //Encoding:
                      encoder.encode(buffer, minBufSize, outBuffer, 0);
  
                      //putting buffer in the packet
                      packet = new DatagramPacket (outBuffer, outBuffer.length, destination,port);
  
                      socket.send(packet);
                  }
  
              } catch(UnknownHostException e) {
                  Log.e("VS", "UnknownHostException");
              } catch (IOException e) {
                  e.printStackTrace();
                  Log.e("VS", "IOException");
              } 
          }
  
      });
      streamThread.start();
   }
  </code></pre>
  
  <p>And the method to play and decoding the stream:</p>
  
  <pre><code>    public void playerAudioDecoding()
  {
      Thread thrd = new Thread(new Runnable() {
          @Override
          public void run() 
          {
              android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
  
              AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, 
                      sampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO, 
                      AudioFormat.ENCODING_PCM_16BIT, minBufSize, 
                      AudioTrack.MODE_STREAM);
              track.play();
  
              Decoder decoder = new G711UCodec();
  
              try
              {
                  DatagramSocket sock = new DatagramSocket(port);
                  byte[] buf = new byte[minBufSize];
  
                  while(true)
                  {
                      DatagramPacket pack = new DatagramPacket(buf, minBufSize);
                      sock.receive(pack);
  
                      //Decoding:
                      int size = pack.getData().length;
                      short[] shortArray = new short[size];
  
                      decoder.decode(shortArray, pack.getData(), minBufSize, 0);
                      byte[] array = MyShortToByte(shortArray);
                      track.write(array, 0, array.length);
                  }
              }
              catch (SocketException se)
              {
                  Log.e("Error", "SocketException: " + se.toString());
              }
              catch (IOException ie)
              {
                  Log.e("Error", "IOException" + ie.toString());
              }
          } // end run
      });
      thrd.start();
  }
  </code></pre>
  
  <p>And it is the codec class that I am using with Apache license:</p>
  
  <pre><code>public class G711UCodec implements Encoder, Decoder {
  // s00000001wxyz...s000wxyz
  // s0000001wxyza...s001wxyz
  // s000001wxyzab...s010wxyz
  // s00001wxyzabc...s011wxyz
  // s0001wxyzabcd...s100wxyz
  // s001wxyzabcde...s101wxyz
  // s01wxyzabcdef...s110wxyz
  // s1wxyzabcdefg...s111wxyz
  
  private static byte[] table13to8 = new byte[8192];
  private static short[] table8to16 = new short[256];
  
  static {
      // b13 --&gt; b8
      for (int p = 1, q = 0; p &lt;= 0x80; p &lt;&lt;= 1, q+=0x10) {
          for (int i = 0, j = (p &lt;&lt; 4) - 0x10; i &lt; 16; i++, j += p) {
              int v = (i + q) ^ 0x7F;
              byte value1 = (byte) v;
              byte value2 = (byte) (v + 128);
              for (int m = j, e = j + p; m &lt; e; m++) {
                  table13to8[m] = value1;
                  table13to8[8191 - m] = value2;
              }
          }
      }
  
      // b8 --&gt; b16
      for (int q = 0; q &lt;= 7; q++) {
          for (int i = 0, m = (q &lt;&lt; 4); i &lt; 16; i++, m++) {
              int v = (((i + 0x10) &lt;&lt; q) - 0x10) &lt;&lt; 3;
              table8to16[m ^ 0x7F] = (short) v;
              table8to16[(m ^ 0x7F) + 128] = (short) (65536 - v);
          }
      }
  }
  
  public int decode(short[] b16, byte[] b8, int count, int offset) {
      for (int i = 0, j = offset; i &lt; count; i++, j++) {
          b16[i] = table8to16[b8[j] &amp; 0xFF];
      }
      return count;
  }
  
  public int encode(short[] b16, int count, byte[] b8, int offset) {
  
      for (int i = 0, j = offset; i &lt; count; i++, j++) {
          b8[j] = table13to8[(b16[i] &gt;&gt; 4) &amp; 0x1FFF];
      }
      return count;
  }
  
  public int getSampleCount(int frameSize) {
      return frameSize;
  }
  </code></pre>
  
  <p>}</p>
  
  <p>Really, I don't know what it happen; If I change the sampleRate  to 4000 I can recognice my voice and some words but there is a lot echo. And i repeat, if disable the encoding/decoding process and make the streaming in PCM, the quality is fantastic. Let see if anybody could help me and thanks in advance.</p>