Skip to content

Commit

Permalink
Audio works now but not good
Browse files Browse the repository at this point in the history
Signed-off-by: Zhou Chang <[email protected]>
  • Loading branch information
Teaonly committed Oct 14, 2014
1 parent 5566749 commit 8f8fec2
Show file tree
Hide file tree
Showing 5 changed files with 269 additions and 19 deletions.
4 changes: 2 additions & 2 deletions assets/js/adpcm.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
function AdpcmDecoder() {
this._inMemory = Module._malloc(1024*64);
this._outMemory = Module._malloc(1024*64);
this._inMemory = Module._malloc(1024*128);
this._outMemory = Module._malloc(1024*128);

this.doDecode = function(inBuffer) {
Module.HEAPU8.set(inBuffer, this._inMemory);
Expand Down
19 changes: 11 additions & 8 deletions assets/js/main.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
var config = {};
config.streamingPort = 8088;

var data = {};
data.mediaSocket = null;
var mediaSocket = null;

var player = null;

var streamer = {};
streamer.onOpen = function() {
Expand All @@ -12,8 +13,8 @@ streamer.onOpen = function() {
streamer.onMessage = function(evt) {
var blob = evt.data;
if ( blob.slice !== undefined) {
media new TeaMedia(blob, function() {
console.log(media);
var media = new TeaMedia(blob, function() {
player.playMedia(media);
}.bind(this) );
}
};
Expand All @@ -24,11 +25,13 @@ streamer.onClose = function() {

// like main function in C
$(document).ready(function() {

var myHost = window.location.hostname;
var wsURL = "ws://" + window.location.hostname + ":" + config.streamingPort;
data.mediaSocket = new WebSocket(wsURL);
mediaSocket = new WebSocket(wsURL);
player = new Player(document.getElementById("videoPlayer"), 8000);

data.mediaSocket.onopen = streamer.onOpen;
data.mediaSocket.onmessage = streamer.onMessage;
data.mediaSocket.onclose = streamer.onClose;
mediaSocket.onopen = streamer.onOpen;
mediaSocket.onmessage = streamer.onMessage;
mediaSocket.onclose = streamer.onClose;
});
86 changes: 86 additions & 0 deletions assets/js/media.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
function TeaMedia(blob, parseDone) {
// vars
this.pcmBlocks = null;
this.nalBlocks = null;

// call backs
this.onParseDone = parseDone;

// public interfaces
this.getPicturePayload = function() {

}.bind(this);

this.getAudioPayload = function() {

}.bind(this);

// internal functions
this._findNext = function(payload, i) {
var info = {'type': 0, 'length': 0};

if ( payload[i] === 0x19
&& payload[i+1] === 0x79
&& payload[i+2] === 0x10
&& payload[i+3] === 0x10) {

info.type = 1;
info.length = (payload[i+7] << 24) + (payload[i+6] << 16) + (payload[i+5] << 8) + payload[i+4];

} else if ( payload[i] === 0x19
&& payload[i+1] === 0x82
&& payload[i+2] === 0x08
&& payload[i+3] === 0x25) {
info.type = 2;
info.length = (payload[i+7] << 24) + (payload[i+6] << 16) + (payload[i+5] << 8) + payload[i+4];
}

return info;

}.bind(this);

this._decodeBuffer = function(arrayBuffer) {
var payload = new Uint8Array(arrayBuffer);

var i = 0;
while(1) {
if ( payload.length - i <= 8) {
// drop left data, because it is not a packet.
break;
}

info = this._findNext(payload, i);
if ( info.type === 1) {
this.nalBlocks.push ( payload.subarray(i+8, i+8+info.length) );
i = i + 8 + info.length;
} else if ( info.type === 2) {
this.pcmBlocks.push ( payload.subarray(i+8, i+8+info.length) );
i = i + 8 + info.length;
} else {
break;
}
}

this.onParseDone();

}.bind(this);

this._constructor = function() {
this.pcmBlocks = [];
this.nalBlocks = [];

var fileReader = new FileReader();
var that = this;
fileReader.onload = function() {
that._decodeBuffer( this.result);
};
fileReader.readAsArrayBuffer(blob);

}.bind(this);




// init
this._constructor();
};
152 changes: 152 additions & 0 deletions assets/js/player.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
function Player (canvas, sampleRate) {
// vars
this._canvas = null;
this._canvasContext = null;

this._avc = null;
this._videoBufferList = null;
this._dummyCanvas = null;
this._dummyCtx = null;


this._sampleRate = -1;
this._audioCtx = null;
this._beginTime = -1;
this._audioBufferList = null;

// call backs
this.onStreamStarvation = null;

// public functions
this._constructor = function() {
this._canvas = canvas;
this._canvasContext = this._canvas.getContext("2d");

window.AudioContext = window.AudioContext || window.webkitAudioContext;
this._audioCtx = new AudioContext();
this._sampleRate = sampleRate;
this._audioBufferList = new Array();



this._avc = new Avc();
this._avc.onPictureDecoded = function(buffer, wid, hei) {
var yuv = new Uint8Array(buffer.length);
yuv.set( buffer, 0, buffer.length);
this._pushVideoBuffer({'yuv':yuv, 'wid':wid, 'hei':hei});
}.bind(this);

this._videoBufferList = new Array();

}.bind(this);

this.playMedia = function(media) {
var i = 0;
var totalLength = 0;
for(i = 0; i < media.pcmBlocks.length; i++) {

var audioDecoder = new AdpcmDecoder();
var pcmData = audioDecoder.doDecode(media.pcmBlocks[i]);
audioDecoder.release();
delete audioDecoder;

this._pushAudioBuffer(pcmData);
}

delete media;
}.bind(this);

// private functions
this._pushAudioBuffer = function(pcmData) {
var source = this._createAudioSource(pcmData);
source.connect(this._audioCtx.destination);

source.onended = function(evt) {
this._audioBufferList.shift();
if ( (this._audioBufferList.length === 0) && (this.onStreamStarvation !== null) ) {
this.onStreamStarvation();
}
this._beginTime = this._audioCtx.currentTime;
}.bind(this);

var bufferedDuration = 0;
var leftDuration = 0;
if ( this._audioBufferList.length > 0) {
for (i = 1; i < this._audioBufferList.length; i++) {
bufferedDuration += this._audioBufferList[i].buffer.duration;
}
leftDuration = this._audioCtx.currentTime - this._beginTime;
} else {
this._beginTime = this._audioCtx.currentTime;
}
this._audioBufferList.push(source);

source.start(leftDuration + bufferedDuration);
}.bind(this);

this._createAudioSource = function(data) {
// create pcm buffer
var pcmShort = new Int16Array(data.length/2);
for(var i = 0, j = 0; i < data.length; i+=2) {
pcmShort[j] = (data[i] & 0xFF) | ((data[i+1] & 0xff) << 8);
j++;
}
var pcmFloat = new Float32Array(pcmShort.length);
for(var i = 0; i < pcmFloat.length; i++) {
pcmFloat[i] = pcmShort[i] / 32768;
}
delete pcmShort;
var audioBuffer = this._audioCtx.createBuffer(1, pcmFloat.length, this._sampleRate);
audioBuffer.getChannelData(0).set(pcmFloat);

// create play source node
var source = this._audioCtx.createBufferSource();
source.buffer = audioBuffer;
return source;
}.bind(this);

this._showPicture = function(picture) {
if ( this._dummyCtx === null) {
this._dummyCanvas = document.createElement("canvas");
this._dummyCanvas.width = picture.wid;
this._dummyCanvas.height = picture.hei;
this._dummyCtx = this._dummyCanvas.getContext("2d");
}

var imageData = this._dummyCtx.createImageData(picture.wid, picture.hei);
yuv2ImageData(picture.yuv, imageData);
this._dummyCtx.putImageData(imageData, 0, 0);

var img = new Image();
img.src = this._dummyCanvas.toDataURL("image/png");
img.onload = function () {
this._canvasContext.drawImage(img, 0, 0, this._canvas.width, this._canvas.height);
delete img;
}.bind(this);
img.onerror = function (stuff) {
console.log("Img Onerror:", stuff);
};
}.bind(this);

this._playVideo = function() {
if ( this._videoBufferList.length >= 2) {
setTimeout(this._playVideo, 200);
}

this._showPicture(this._videoBufferList[0] );
delete this._videoBufferList[0].payload;
this._videoBufferList.shift();
}.bind(this);

this._pushVideoBuffer = function(picture) {
this._videoBufferList.push(picture);

if ( this._videoBufferList.length === 1) {
setTimeout(this._playVideo, 10);
}

}.bind(this);

// init
this._constructor();
}
27 changes: 18 additions & 9 deletions src/teaonly/droideye/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ public void onPause() {

if ( webServer != null)
webServer.stop();

audioCapture.release();
if ( audioCapture != null)
audioCapture.release();

if ( cameraView != null) {
previewLock.lock();
Expand Down Expand Up @@ -160,9 +160,11 @@ public void onCameraReady() {

nativeInitMediaEncoder(cameraView.Width(), cameraView.Height());

audioCapture.startRecording();
AudioEncoder audioEncoder = new AudioEncoder();
audioEncoder.start();
if ( audioCapture != null) {
audioCapture.startRecording();
AudioEncoder audioEncoder = new AudioEncoder();
audioEncoder.start();
}

cameraView.StartPreview();
}
Expand Down Expand Up @@ -207,11 +209,15 @@ private void initAudio() {
targetSize = minBufferSize;
}
if (audioCapture == null) {
audioCapture = new AudioRecord(MediaRecorder.AudioSource.MIC,
16000,
try {
audioCapture = new AudioRecord(MediaRecorder.AudioSource.MIC,
8000,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
targetSize);
} catch (IllegalArgumentException e) {
audioCapture = null;
}
}

}
Expand Down Expand Up @@ -348,7 +354,7 @@ private class AudioEncoder extends Thread {
private byte[] audioPacket = new byte[1024*1024];
private byte[] audioHeader = new byte[8];

int packageSize = 3200;
int packageSize = 16000;

public AudioEncoder () {
audioHeader[0] = (byte)0x19;
Expand Down Expand Up @@ -378,7 +384,10 @@ public void run() {

synchronized (MainActivity.this) {
currentBlock.write( audioHeader, 8);
currentBlock.write( audioPacket, ret);
ret = currentBlock.write( audioPacket, ret);
if ( ret == 0) {
Log.d(TAG, ">>>>>>> lost audio in Java>>>");
}
}
}
}
Expand Down

0 comments on commit 8f8fec2

Please sign in to comment.