JavaCPP FFMpeg to JavaSound - audio

I have a problem to be able to read audio using JavaCPP FFMpeg library. I don’t know how to pass it to java sound and I don’t know too if my code is correct.
Let’s see the more important part of my code (video is OK so I drop this) :
The variables :
//==========================================================================
// FFMpeg 4.x - Video and Audio
//==========================================================================
private final AVFormatContext pFormatCtx = new AVFormatContext(null);
private final AVDictionary OPTIONS_DICT = null;
private AVPacket pPacket = new AVPacket();
//==========================================================================
// FFMpeg 4.x - Audio
//==========================================================================
private AVCodec pAudioCodec;
private AVCodecContext pAudioCodecCtx;
private final List<StreamInfo> audioStreams = new ArrayList<>();
private int audio_data_size;
private final BytePointer audio_data = new BytePointer(0);
private int audio_ret;
private AVFrame pAudioDecodedFrame = null;
private AVCodecParserContext pAudioParser;
private SwrContext audio_swr_ctx = null;
Then I call prepare functions in this order :
private void prepareFirst() throws Exception{
oldFile = file;
// Initialize packet and check for error
pPacket = av_packet_alloc();
if(pPacket == null){
throw new Exception("ALL: Couldn't allocate packet");
}
// Open video file
if (avformat_open_input(pFormatCtx, file.getPath(), null, null) != 0) {
throw new Exception("ALL: Couldn't open file");
}
// Retrieve stream information
if (avformat_find_stream_info(pFormatCtx, (PointerPointer)null) < 0) {
throw new Exception("ALL: Couldn't find stream information");
}
// Dump information about file onto standard error
av_dump_format(pFormatCtx, 0, file.getPath(), 0);
// Find the first audio/video stream
for (int i = 0; i < pFormatCtx.nb_streams(); i++) {
switch(pFormatCtx.streams(i).codecpar().codec_type()){
case AVMEDIA_TYPE_VIDEO -> videoStreams.add(new StreamInfo(i, pFormatCtx.streams(i)));
case AVMEDIA_TYPE_AUDIO -> audioStreams.add(new StreamInfo(i, pFormatCtx.streams(i)));
}
}
if(videoStreams.isEmpty() && type != PlayType.AudioOnly){
throw new Exception("Didn't find an audio stream");
}
if(audioStreams.isEmpty() && type != PlayType.VideoOnly){
throw new Exception("Didn't find a video stream");
}
}
private void prepareAudio() throws Exception{
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// AUDIO
//------------------------------------------------------------------
if(audioStreams.isEmpty() == false){
//===========================
//------------
// // Let's search for AVCodec
// pAudioCodec = avcodec_find_decoder(pFormatCtx.streams(audioStreams.get(0).getStreamIndex()).codecpar().codec_id());
// if (pAudioCodec == null) {
// throw new Exception("AUDIO: Unsupported codec or not found!");
// }
//
// // Let's alloc AVCodecContext
// pAudioCodecCtx = avcodec_alloc_context3(pAudioCodec);
// if (pAudioCodecCtx == null) {
// throw new Exception("AUDIO: Unallocated codec context or not found!");
// }
// Get a pointer to the codec context for the video stream
pAudioCodecCtx = pFormatCtx.streams(audioStreams.get(0).getStreamIndex()).codec();
// Find the decoder for the video stream
pAudioCodec = avcodec_find_decoder(pAudioCodecCtx.codec_id());
if (pAudioCodec == null) {
throw new Exception("AUDIO: Unsupported codec or not found!");
}
//===========================
//------------
/* open it */
if (avcodec_open2(pAudioCodecCtx, pAudioCodec, OPTIONS_DICT) < 0) {
throw new Exception("AUDIO: Could not open codec");
}
pAudioDecodedFrame = av_frame_alloc();
if (pAudioDecodedFrame == null){
throw new Exception("AUDIO: DecodedFrame allocation failed");
}
audio_swr_ctx = swr_alloc_set_opts(
null, // existing Swr context or NULL
AV_CH_LAYOUT_STEREO, // output channel layout (AV_CH_LAYOUT_*)
AV_SAMPLE_FMT_S16, // output sample format (AV_SAMPLE_FMT_*).
44100, // output sample rate (frequency in Hz)
pAudioCodecCtx.channels(), // input channel layout (AV_CH_LAYOUT_*)
pAudioCodecCtx.sample_fmt(), // input sample format (AV_SAMPLE_FMT_*).
pAudioCodecCtx.sample_rate(), // input sample rate (frequency in Hz)
0, // logging level offset
null // parent logging context, can be NULL
);
swr_init(audio_swr_ctx);
av_samples_fill_arrays(
pAudioDecodedFrame.data(), // audio_data,
pAudioDecodedFrame.linesize(), // linesize
audio_data, // buf
(int)AV_CH_LAYOUT_STEREO, // nb_channels
44100, // nb_samples
AV_SAMPLE_FMT_S16, // sample_fmt
0 // align
);
}
// Audio treatment end ---------------------------------------------
//==================================================================
}
And then when I launch the thread :
private void doPlay() throws Exception{
av_init_packet(pPacket);
// Read frames
while (av_read_frame(pFormatCtx, pPacket) >= 0) {
if (type != PlayType.AudioOnly && pPacket.stream_index() == videoStreams.get(0).getStreamIndex()) {
// Is this a packet from the video stream?
decodeVideo();
renewPacket();
}
if (type != PlayType.VideoOnly && pPacket.stream_index() == audioStreams.get(0).getStreamIndex()) {
// Is this a packet from the audio stream?
if(pPacket.size() > 0){
decodeAudio();
renewPacket();
}
}
}
}
private void renewPacket(){
// Free the packet that was allocated by av_read_frame
av_packet_unref(pPacket);
pPacket.data(null);
pPacket.size(0);
av_init_packet(pPacket);
}
And again, this is where I don’t read audio :
private void decodeAudio() throws Exception{
do {
audio_ret = avcodec_send_packet(pAudioCodecCtx, pPacket);
} while(audio_ret == AVERROR_EAGAIN());
System.out.println("packet sent return value: " + audio_ret);
if(audio_ret == AVERROR_EOF || audio_ret == AVERROR_EINVAL()) {
StringBuilder sb = new StringBuilder();
Formatter formatter = new Formatter(sb, Locale.US);
formatter.format("AVERROR(EAGAIN): %d, AVERROR_EOF: %d, AVERROR(EINVAL): %d\n", AVERROR_EAGAIN(), AVERROR_EOF, AVERROR_EINVAL());
formatter.format("Audio frame getting error (%d)!\n", audio_ret);
throw new Exception(sb.toString());
}
audio_ret = avcodec_receive_frame(pAudioCodecCtx, pAudioDecodedFrame);
System.out.println("frame received return value: " + audio_ret);
audio_data_size = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
if (audio_data_size < 0) {
/* This should not occur, checking just for paranoia */
throw new Exception("Failed to calculate data size");
}
double frame_nb = 44100d / pAudioCodecCtx.sample_rate() * pAudioDecodedFrame.nb_samples();
long out_count = Math.round(Math.floor(frame_nb));
int out_samples = swr_convert(
audio_swr_ctx,
audio_data,
(int)out_count,
pAudioDecodedFrame.data(0),
pAudioDecodedFrame.nb_samples()
);
if (out_samples < 0) {
throw new Exception("AUDIO: Error while converting");
}
int dst_bufsize = av_samples_get_buffer_size(
pAudioDecodedFrame.linesize(),
(int)AV_CH_LAYOUT_STEREO,
out_samples,
AV_SAMPLE_FMT_S16,
1
);
AudioFormat audioFormat = new AudioFormat(
pAudioDecodedFrame.sample_rate(),
16,
2,
true,
false
);
BytePointer bytePointer = pAudioDecodedFrame.data(0);
ByteBuffer byteBuffer = bytePointer.asBuffer();
byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);
try (SourceDataLine sdl = AudioSystem.getSourceDataLine(audioFormat)) {
sdl.open(audioFormat);
sdl.start();
sdl.write(bytes, 0, bytes.length);
sdl.drain();
sdl.stop();
} catch (LineUnavailableException ex) {
Logger.getLogger(AVEntry.class.getName()).log(Level.SEVERE, null, ex);
}
}
Do you have an idea ?

Related

Detect voice by audio recorder in android studio

Well, I would like to implement a function, such when the application starts, the recorder will start to recording, and when the user keeps silence there is nothing going to happen until the user speaks. Then, it will save the PCM file of user's voice and then stop recording.
Voice Detection in Android Application
Above is the question I have found similar as mine, but the answer of this link can not work. And I don't know how to modify it, since I don't understand the concept of the code.
Please help me~
Well, I solved my problem, here is my solution.
I modified the code came from this url:
Voice Detection in Android Application
private static final String TAG = "MainActivity";
private static int RECORDER_SAMPLERATE = 44100;
private static int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_STEREO;
private static int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
private Button btn, btn_convert, btn_play;
private TextView txv;
boolean isRecording = false;
private File file;
private AudioRecord audioRecord;
int bufferSizeInBytes = 0;
Context context = MainActivity.this;
// path
final String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/final.pcm" ;
final String outpath = path.replace(".pcm", ".wav");
public void autoRecording(){
// Get the minimum buffer size required for the successful creation of an AudioRecord object.
bufferSizeInBytes = AudioRecord.getMinBufferSize( RECORDER_SAMPLERATE,
RECORDER_CHANNELS,
RECORDER_AUDIO_ENCODING
);
// Initialize Audio Recorder.
AudioRecord audioRecorder = new AudioRecord( MediaRecorder.AudioSource.MIC,
RECORDER_SAMPLERATE,
RECORDER_CHANNELS,
RECORDER_AUDIO_ENCODING,
bufferSizeInBytes
);
// Start Recording.
txv.setText("Ing");
audioRecorder.startRecording();
isRecording = true;
// for auto stop
int numberOfReadBytes = 0;
byte audioBuffer[] = new byte[bufferSizeInBytes];
boolean recording = false;
float tempFloatBuffer[] = new float[3];
int tempIndex = 0;
// create file
file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/final.pcm");
Log.d(TAG, "recording: file path:" + file.toString());
if (file.exists()){
Log.d(TAG,"file exist, delete file");
file.delete();
}
try {
Log.d(TAG,"file created");
file.createNewFile();
} catch (IOException e) {
Log.d(TAG,"didn't create the file:" + e.getMessage());
throw new IllegalStateException("did not create file:" + file.toString());
}
// initiate media scan and put the new things into the path array to
// make the scanner aware of the location and the files you want to see
MediaScannerConnection.scanFile(context, new String[] {file.toString()}, null, null);
// output stream
OutputStream os = null;
DataOutputStream dos = null;
try {
os = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(os);
dos = new DataOutputStream(bos);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// While data come from microphone.
while( true )
{
float totalAbsValue = 0.0f;
short sample = 0;
numberOfReadBytes = audioRecorder.read( audioBuffer, 0, bufferSizeInBytes );
// Analyze Sound.
for( int i=0; i<bufferSizeInBytes; i+=2 )
{
sample = (short)( (audioBuffer[i]) | audioBuffer[i + 1] << 8 );
totalAbsValue += (float)Math.abs( sample ) / ((float)numberOfReadBytes/(float)2);
}
// read in file
for (int i = 0; i < numberOfReadBytes; i++) {
try {
dos.writeByte(audioBuffer[i]);
} catch (IOException e) {
e.printStackTrace();
}
}
// Analyze temp buffer.
tempFloatBuffer[tempIndex%3] = totalAbsValue;
float temp = 0.0f;
for( int i=0; i<3; ++i )
temp += tempFloatBuffer[i];
if( (temp >=0 && temp <= 2100) && recording == false ) // the best number for close to device: 3000
{ // the best number for a little bit distance : 2100
Log.i("TAG", "1");
tempIndex++;
continue;
}
if( temp > 2100 && recording == false )
{
Log.i("TAG", "2");
recording = true;
}
if( (temp >= 0 && temp <= 2100) && recording == true )
{
Log.i("TAG", "final run");
//isRecording = false;
txv.setText("Stop Record.");
//*/
tempIndex++;
audioRecorder.stop();
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
}
The function of this function:
if you call this function, the recorder will start recording, and once you make sound(Notify if there are some noise it will stop too.) it will stop recording and save into file(pcm format).

NAudio Mp3 decoding click and pops

I followed this NAudio Demo modified to play ShoutCast.
In my full code I have to resample the incoming audio and stream it again over the network to a network player. Since I get many "clicks and pops", I came back to the demo code and I found that these artifacts are originated after the decoding block.
If I save the incoming stream in mp3 format, it is pretty clear.
When I save the raw decoded data (without other processing than the decoder) I get many audio artifacts.
I wonder whether I am doing some error, even if my code is almost equal to the NAudio demo.
Here the function from the example as modified by me to save the raw data. It is called as a new Thread.
private void StreamMP3(object state)
{
//Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
//SettingsSection section = (SettingsSection)config.GetSection("system.net/settings");
this.fullyDownloaded = false;
string url = "http://icestreaming.rai.it/5.mp3";//(string)state;
webRequest = (HttpWebRequest)WebRequest.Create(url);
int metaInt = 0; // blocksize of mp3 data
int framesize = 0;
webRequest.Headers.Clear();
webRequest.Headers.Add("GET", "/ HTTP/1.0");
// needed to receive metadata informations
webRequest.Headers.Add("Icy-MetaData", "1");
webRequest.UserAgent = "WinampMPEG/5.09";
HttpWebResponse resp = null;
try
{
resp = (HttpWebResponse)webRequest.GetResponse();
}
catch (WebException e)
{
if (e.Status != WebExceptionStatus.RequestCanceled)
{
ShowError(e.Message);
}
return;
}
byte[] buffer = new byte[16384 * 4]; // needs to be big enough to hold a decompressed frame
try
{
// read blocksize to find metadata block
metaInt = Convert.ToInt32(resp.GetResponseHeader("icy-metaint"));
}
catch
{
}
IMp3FrameDecompressor decompressor = null;
byteOut = createNewFile(destPath, "salva", "raw");
try
{
using (var responseStream = resp.GetResponseStream())
{
var readFullyStream = new ReadFullyStream(responseStream);
readFullyStream.metaInt = metaInt;
do
{
if (mybufferedWaveProvider != null && mybufferedWaveProvider.BufferLength - mybufferedWaveProvider.BufferedBytes < mybufferedWaveProvider.WaveFormat.AverageBytesPerSecond / 4)
{
Debug.WriteLine("Buffer getting full, taking a break");
Thread.Sleep(500);
}
else
{
Mp3Frame frame = null;
try
{
frame = Mp3Frame.LoadFromStream(readFullyStream, true);
if (metaInt > 0)
UpdateSongName(readFullyStream.SongName);
else
UpdateSongName("No Song Info in Stream...");
}
catch (EndOfStreamException)
{
this.fullyDownloaded = true;
// reached the end of the MP3 file / stream
break;
}
catch (WebException)
{
// probably we have aborted download from the GUI thread
break;
}
if (decompressor == null)
{
// don't think these details matter too much - just help ACM select the right codec
// however, the buffered provider doesn't know what sample rate it is working at
// until we have a frame
WaveFormat waveFormat = new Mp3WaveFormat(frame.SampleRate, frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frame.FrameLength, frame.BitRate);
decompressor = new AcmMp3FrameDecompressor(waveFormat);
this.mybufferedWaveProvider = new BufferedWaveProvider(decompressor.OutputFormat);
this.mybufferedWaveProvider.BufferDuration = TimeSpan.FromSeconds(200); // allow us to get well ahead of ourselves
framesize = (decompressor.OutputFormat.Channels * decompressor.OutputFormat.SampleRate * (decompressor.OutputFormat.BitsPerSample / 8) * 20) / 1000;
//this.bufferedWaveProvider.BufferedDuration = 250;
}
int decompressed = decompressor.DecompressFrame(frame, buffer, 0);
//Debug.WriteLine(String.Format("Decompressed a frame {0}", decompressed));
mybufferedWaveProvider.AddSamples(buffer, 0, decompressed);
while (mybufferedWaveProvider.BufferedDuration.Milliseconds >= 20)
{
byte[] read = new byte[framesize];
mybufferedWaveProvider.Read(read, 0, framesize);
byteOut.Write(read, 0, framesize);
}
}
} while (playbackState != StreamingPlaybackState.Stopped);
Debug.WriteLine("Exiting");
// was doing this in a finally block, but for some reason
// we are hanging on response stream .Dispose so never get there
decompressor.Dispose();
}
}
finally
{
if (decompressor != null)
{
decompressor.Dispose();
}
}
}
OK i found the problem. I included the shoutcast metadata to the MP3Frame.
See the comment "HERE I COLLECT THE BYTES OF THE MP3 FRAME" to locate the correct point to get the MP3 frame with no streaming metadata.
The following code runs without audio artifacts:
private void SHOUTcastReceiverThread()
{
//-*- String server = "http://216.235.80.18:8285/stream";
//String serverPath = "/";
//String destPath = "C:\\temp\\"; // destination path for saved songs
HttpWebRequest request = null; // web request
HttpWebResponse response = null; // web response
int metaInt = 0; // blocksize of mp3 data
int count = 0; // byte counter
int metadataLength = 0; // length of metadata header
string metadataHeader = ""; // metadata header that contains the actual songtitle
string oldMetadataHeader = null; // previous metadata header, to compare with new header and find next song
//CircularQueueStream framestream = new CircularQueueStream(2048);
QueueStream framestream = new QueueStream();
framestream.Position = 0;
bool bNewSong = false;
byte[] buffer = new byte[512]; // receive buffer
byte[] dec_buffer = new byte[decSIZE];
Mp3Frame frame;
IMp3FrameDecompressor decompressor = null;
Stream socketStream = null; // input stream on the web request
// create web request
request = (HttpWebRequest)WebRequest.Create(server);
// clear old request header and build own header to receive ICY-metadata
request.Headers.Clear();
request.Headers.Add("GET", serverPath + " HTTP/1.0");
request.Headers.Add("Icy-MetaData", "1"); // needed to receive metadata informations
request.UserAgent = "WinampMPEG/5.09";
// execute request
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
// read blocksize to find metadata header
metaInt = Convert.ToInt32(response.GetResponseHeader("icy-metaint"));
try
{
// open stream on response
socketStream = response.GetResponseStream();
var readFullyStream = new ReadFullyStream(socketStream);
frame = null;
// rip stream in an endless loop
do
{
if (IsBufferNearlyFull)
{
Debug.WriteLine("Buffer getting full, taking a break");
Thread.Sleep(500);
frame = null;
}
else
{
int bufLen = readFullyStream.Read(buffer, 0, buffer.Length);
try
{
if (framestream.CanRead && framestream.Length > 512)
frame = Mp3Frame.LoadFromStream(framestream);
else
frame = null;
}
catch (Exception ex)
{
frame = null;
}
if (bufLen < 0)
{
Debug.WriteLine("Buffer error 1: exit.");
return;
}
// processing RAW data
for (int i = 0; i < bufLen; i++)
{
// if there is a header, the 'headerLength' would be set to a value != 0. Then we save the header to a string
if (metadataLength != 0)
{
metadataHeader += Convert.ToChar(buffer[i]);
metadataLength--;
if (metadataLength == 0) // all metadata informations were written to the 'metadataHeader' string
{
string fileName = "";
string fileNameRaw = "";
// if songtitle changes, create a new file
if (!metadataHeader.Equals(oldMetadataHeader))
{
// flush and close old byteOut stream
if (byteOut != null)
{
byteOut.Flush();
byteOut.Close();
byteOut = null;
}
if (byteOutRaw != null)
{
byteOutRaw.Flush();
byteOutRaw.Close();
byteOutRaw = null;
}
timeStart = timeEnd;
// extract songtitle from metadata header. Trim was needed, because some stations don't trim the songtitle
//fileName = Regex.Match(metadataHeader, "(StreamTitle=')(.*)(';StreamUrl)").Groups[2].Value.Trim();
fileName = Regex.Match(metadataHeader, "(StreamTitle=')(.*)(';)").Groups[2].Value.Trim();
// write new songtitle to console for information
if (fileName.Length == 0)
fileName = "shoutcast_test";
fileNameRaw = fileName + "_raw";
framestream.reSetPosition();
SongChanged(this, metadataHeader);
bNewSong = true;
// create new file with the songtitle from header and set a stream on this file
timeEnd = DateTime.Now;
if (bWrite_to_file)
{
byteOut = createNewFile(destPath, fileName, "mp3");
byteOutRaw = createNewFile(destPath, fileNameRaw, "raw");
}
timediff = timeEnd - timeStart;
// save new header to 'oldMetadataHeader' string, to compare if there's a new song starting
oldMetadataHeader = metadataHeader;
}
metadataHeader = "";
}
}
else // write mp3 data to file or extract metadata headerlength
{
if (count++ < metaInt) // write bytes to filestream
{
//HERE I COLLECT THE BYTES OF THE MP3 FRAME
framestream.Write(buffer, i, 1);
}
else // get headerlength from lengthbyte and multiply by 16 to get correct headerlength
{
metadataLength = Convert.ToInt32(buffer[i]) * 16;
count = 0;
}
}
}//for
if (bNewSong)
{
decompressor = createDecompressor(frame);
bNewSong = false;
}
if (frame != null && decompressor != null)
{
framedec(decompressor, frame);
}
// fine Processing dati RAW
}//Buffer is not full
SHOUTcastStatusProcess();
} while (playbackState != StreamingPlaybackState.Stopped);
} //try
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
if (byteOut != null)
byteOut.Close();
if (socketStream != null)
socketStream.Close();
if (decompressor != null)
{
decompressor.Dispose();
decompressor = null;
}
if (null != request)
request.Abort();
if (null != framestream)
framestream.Dispose();
if (null != bufferedWaveProvider)
bufferedWaveProvider.ClearBuffer();
//if (null != bufferedWaveProviderOut)
// bufferedWaveProviderOut.ClearBuffer();
if (null != mono16bitFsinStream)
{
mono16bitFsinStream.Close();
mono16bitFsinStream.Dispose();
}
if (null != middleStream2)
{
middleStream2.Close();
middleStream2.Dispose();
}
if (null != resampler)
resampler.Dispose();
}
}
public class QueueStream : MemoryStream
{
long ReadPosition = 0;
long WritePosition = 0;
public QueueStream() : base() { }
public override int Read(byte[] buffer, int offset, int count)
{
Position = ReadPosition;
var temp = base.Read(buffer, offset, count);
ReadPosition = Position;
return temp;
}
public override void Write(byte[] buffer, int offset, int count)
{
Position = WritePosition;
base.Write(buffer, offset, count);
WritePosition = Position;
}
public void reSetPosition()
{
WritePosition = 0;
ReadPosition = 0;
Position = 0;
}
}
private void framedec(IMp3FrameDecompressor decompressor, Mp3Frame frame)
{
int Ndecoded_samples = 0;
byte[] dec_buffer = new byte[decSIZE];
Ndecoded_samples = decompressor.DecompressFrame(frame, dec_buffer, 0);
bufferedWaveProvider.AddSamples(dec_buffer, 0, Ndecoded_samples);
NBufferedSamples += Ndecoded_samples;
brcnt_in.incSamples(Ndecoded_samples);
if (Ndecoded_samples > decSIZE)
{
Debug.WriteLine(String.Format("Too many samples {0}", Ndecoded_samples));
}
if (byteOut != null)
byteOut.Write(frame.RawData, 0, frame.RawData.Length);
if (byteOutRaw != null) // as long as we don't have a songtitle, we don't open a new file and don't write any bytes
byteOutRaw.Write(dec_buffer, 0, Ndecoded_samples);
frame = null;
}
private IMp3FrameDecompressor createDecompressor(Mp3Frame frame)
{
IMp3FrameDecompressor dec = null;
if (frame != null)
{
// don't think these details matter too much - just help ACM select the right codec
// however, the buffered provider doesn't know what sample rate it is working at
// until we have a frame
WaveFormat srcwaveFormat = new Mp3WaveFormat(frame.SampleRate, frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frame.FrameLength, frame.BitRate);
dec = new AcmMp3FrameDecompressor(srcwaveFormat);
bufferedWaveProvider = new BufferedWaveProvider(dec.OutputFormat);// decompressor.OutputFormat
bufferedWaveProvider.BufferDuration = TimeSpan.FromSeconds(400); // allow us to get well ahead of ourselves
// ------------------------------------------------
//Create an intermediate format with same sampling rate, 16 bit, mono
middlewavformat = new WaveFormat(dec.OutputFormat.SampleRate, 16, 1);
outwavFormat = new WaveFormat(Fs_out, 16, 1);
// wave16ToFloat = new Wave16ToFloatProvider(provider); // I have tried with and without this converter.
wpws = new WaveProviderToWaveStream(bufferedWaveProvider);
//Check middlewavformat.Encoding == WaveFormatEncoding.Pcm;
mono16bitFsinStream = new WaveFormatConversionStream(middlewavformat, wpws);
middleStream2 = new BlockAlignReductionStream(mono16bitFsinStream);
resampler = new MediaFoundationResampler(middleStream2, outwavFormat);
}
return dec;
}

texture view is not working with mediacodec for decoding below api 21

The following code is working with API 21 and above. However, when I run it on below 21, no data shows up on TextureView.
My configuration for MediaCodec:
MediaFormat format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 1920, 1080);
format.setByteBuffer("csd-0", ByteBuffer.allocate(100));
format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 100000);
try {
m_codec = MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
m_codec.configure(format, new Surface(m_surface.getSurfaceTexture()), null, 0);
m_codec.start();
} catch (Exception e) {
e.printStackTrace();
}
The decoding part:
int inputIndex = m_codec.dequeueInputBuffer(-1);
if (inputIndex >= 0) {
ByteBuffer buffer;
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
buffer = m_codec.getInputBuffer(inputIndex);
buffer.clear();
}
else {
buffer=m_codec.getInputBuffers()[inputIndex];
buffer.put(videoBuffer,0,info.size);
}
if (buffer != null) {
buffer.put(videoBuffer, info.offset,videoBuffer.length);
m_codec.queueInputBuffer(inputIndex, 0, videoBuffer.length, 0, 0);
}
}
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
int outputIndex = m_codec.dequeueOutputBuffer(info, 0);
if (outputIndex >= 0) {
m_codec.releaseOutputBuffer(outputIndex, true);
}
EDIT:
I got the solution,when i removed below line, now it's working
format.setByteBuffer("csd-0", ByteBuffer.allocate(100));

Unable to read message from Service bus. it is returning null

I am trying to read the stream that is on Azure Service bus. But I am getting null bytes. File size that is getting created is same as the size of the bytes that are being sent, but it contains all nulls. I have added the code that is used for converting Stream to Byte array with the function name ReadAllBytes(Stream source)
below is the code for reference:
static void Main(string[] args)
{
MemoryStream largeMessageStream = new MemoryStream();
#region ReceiveMessage
var msg = Microsoft.ServiceBus.NamespaceManager.CreateFromConnectionString(ConfigurationSettings.AppSettings["Microsoft.ServiceBus.ConnectionString"].ToString());
var numofmessages = msg.GetQueue(AccountDetails.QueueName).MessageCountDetails.ActiveMessageCount.ToString();
if (msg.GetQueue(AccountDetails.QueueName).RequiresSession)
{
var queueClient1 = QueueClient.CreateFromConnectionString(ConfigurationSettings.AppSettings["Microsoft.ServiceBus.ConnectionString"].ToString(), AccountDetails.QueueName);
var session = queueClient1.AcceptMessageSession();
Console.WriteLine("Message session Id: " + session.SessionId);
Console.Write("Receiving sub messages");
while (true)
{
// Receive a sub message
BrokeredMessage subMessage = session.Receive(TimeSpan.FromSeconds(5));
if (subMessage != null)
{
// Copy the sub message body to the large message stream.
Stream subMessageStream = subMessage.GetBody<Stream>();
subMessageStream.CopyTo(largeMessageStream);
// Mark the message as complete.
subMessage.Complete();
Console.Write(".");
}
else
{
// The last message in the sequence is our completeness criteria.
Console.WriteLine("Done!");
break;
}
}
// Create an aggregated message from the large message stream.
BrokeredMessage largeMessage = new BrokeredMessage(largeMessageStream, true);
Console.WriteLine("Received message");
Console.WriteLine("Message body size: " + largeMessageStream.Length);
string testFile = #"D:\Dev\csvData1.csv";
Console.WriteLine("Saving file: " + testFile);
// Save the message body as a file.
Stream resultStream = largeMessage.GetBody<Stream>();
byte[] x = ReadAllBytes(resultStream);
File.WriteAllBytes(testFile, x);
}
public static byte[] ReadAllBytes(Stream source)
{
long originalPosition = source.Position;
source.Position = 0;
try
{
byte[] readBuffer = new byte[source.Length];
int totalBytesRead = 0;
int bytesRead;
while ((bytesRead = source.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
{
totalBytesRead += bytesRead;
if (totalBytesRead == readBuffer.Length)
{
int nextByte = source.ReadByte();
if (nextByte != -1)
{
byte[] temp = new byte[readBuffer.Length * 2];
Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
readBuffer = temp;
totalBytesRead++;
}
}
}
byte[] buffer = readBuffer;
if (readBuffer.Length != totalBytesRead)
{
buffer = new byte[totalBytesRead];
Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
}
return buffer;
}
finally
{
source.Position = originalPosition;
}
}
I send a message with stream body using the following code, and then I receive the message and test your code on my side, the code works for me.
using (MemoryStream stream = new MemoryStream(File.ReadAllBytes(#"C:\Users\xxx\Desktop\source.txt")))
{
client.Send(new BrokeredMessage(stream));
}
My source.txt
"ID", "Age", "Rich", "timestamp"
1, "50", "Y", "2017-06-06 14:19:21.77"
2, "22", "N", "2017-06-06 14:19:21.77"
Byte array
Console app output
csvData1.csv
If possible, you can try to send a new message with stream body and execute your code to check if it can works fine.

Bluetooth LE with Android Studio: Write Characteristic with buttons

I am new to Android and Bluetooth and suffering with this problem.
I want to write on a specific characteristic if two buttons are touched.
If I touch the first button a number between 0-9 should be count with +1. With the other button the number should be decrease with -1.
As a fundament i use the BluetootleGatt Example App from Google.
In the DeviceControlActivity i changed the following code:
private final ExpandableListView.OnChildClickListener servicesListClickListner =
new ExpandableListView.OnChildClickListener() {
#Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
int childPosition, long id) {
if (mGattCharacteristics != null) {
final BluetoothGattCharacteristic characteristic =
mGattCharacteristics.get(groupPosition).get(childPosition);
final int charaProp = characteristic.getProperties(); //The properties contain a bit mask of property flags indicating
//the features of this characteristic.
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
// If there is an active notification on a characteristic, clear
// it first so it doesn't update the data field on the user interface.
if (mNotifyCharacteristic != null) {
mBluetoothLeService.setCharacteristicNotification(
mNotifyCharacteristic, false);
mNotifyCharacteristic = null;
}
mBluetoothLeService.readCharacteristic(characteristic);
}
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY ) > 0) {
mNotifyCharacteristic = characteristic;
mBluetoothLeService.setCharacteristicNotification(
characteristic, true);
}
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_WRITE) > 0) {
characteristic.setWriteType(BluetoothGattCharacteristic.PERMISSION_WRITE);
addListenerOnButton();
}
return true;
}
return false;
}
};
Here is my addListenerOnButton() for the two buttons:
public void addListenerOnButton() {
mArrowUp = (ImageButton) findViewById(R.id.arrow_up);
mArrowUp.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
mBluetoothLeService.writeCharacteristicUp();
}
});
mArrowDown = (ImageButton) findViewById(R.id.arrow_down);
mArrowDown.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
mBluetoothLeService.writeCharacteristicDown();
}
});
}
They will call the two writeCharacteristic Methods in the BluetoothLeService-Class. For example i post here only the writeCharacteristicUp()-Method:
public boolean writeCharacteristicUp() {
//check mBluetoothGatt is available
if (mBluetoothGatt == null) {
Log.e(TAG, "lost connection");
return false;
}
BluetoothGattService Service = mBluetoothGatt.getService(UUID_DO_LOGGER_TEST);
if (Service == null) {
Log.e(TAG, "service not found!");
return false;
}
BluetoothGattCharacteristic charac = Service
.getCharacteristic(UUID_TEST_NUMBER);
if (charac == null) {
Log.e(TAG, "char not found!");
return false;
}
byte[] value0 = new byte[1];
value0[0] = (byte) 0; //Constant of 0 for comparison later
byte[] value1 = new byte[1];
value1[0] = (byte) 1; //Constant of 1 for comparison later
byte[] value2 = new byte[1];
value2[0] = (byte) 2; //Constant of 1 for comparison later
byte[] value3 = new byte[1];
value3[0] = (byte) 3; //Constant of 1 for comparison later
byte[] value4 = new byte[1];
value4[0] = (byte) 4; //Constant of 1 for comparison later
byte[] value5 = new byte[1];
value5[0] = (byte) 5; //Constant of 1 for comparison later
byte[] value6 = new byte[1];
value6[0] = (byte) 6; //Constant of 1 for comparison later
byte[] value7 = new byte[1];
value7[0] = (byte) 7; //Constant of 1 for comparison later
byte[] value8 = new byte[1];
value8[0] = (byte) 8; //Constant of 1 for comparison later
byte[] value9 = new byte[1];
value9[0] = (byte) 9; //Constant of 1 for comparison later
byte[] actualvalue = charac.getValue();
if (actualvalue == value0) {
charac.setValue(value1);
}
if (actualvalue == value1) {
charac.setValue(value2);
}
if (actualvalue == value2) {
charac.setValue(value3);
}
if (actualvalue == value3) {
charac.setValue(value4);
}
if (actualvalue == value4) {
charac.setValue(value5);
}
if (actualvalue == value5) {
charac.setValue(value6);
}
if (actualvalue == value6) {
charac.setValue(value7);
}
if (actualvalue == value7) {
charac.setValue(value8);
}
if (actualvalue == value8) {
charac.setValue(value9);
}
if (actualvalue == value9) {
charac.setValue(value0);
}
// charac.setValue(value0);
// byte[] actualvaluenew1 = charac.getValue();
boolean status = mBluetoothGatt.writeCharacteristic(charac);
// byte[] actualvaluenew2 = charac.getValue();
return status;
}
The problem is that the
boolean status = mBluetoothGatt.writeCharacteristic(charac)
does not work, the status will be false. And so the actual value is not displayed on the Screen in the corresponding TextView. Why?
Also i found out that the if-grinds are not working because charac.setValue(value0) is only working outside the if-grinds?
I would suggest you press and hold control key and click to BluetoothGatt#writeCharacteristic(ch) function in your code. Then Android Studio will view BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic characteristic) function:
public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) {
if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0
&& (characteristic.getProperties() &
BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) return false;
if (VDBG) Log.d(TAG, "writeCharacteristic() - uuid: " + characteristic.getUuid());
if (mService == null || mClientIf == 0 || characteristic.getValue() == null) return false;
BluetoothGattService service = characteristic.getService();
if (service == null) return false;
BluetoothDevice device = service.getDevice();
if (device == null) return false;
synchronized(mDeviceBusy) {
if (mDeviceBusy) return false;
mDeviceBusy = true;
}
try {
mService.writeCharacteristic(mClientIf, device.getAddress(),
service.getType(), service.getInstanceId(),
new ParcelUuid(service.getUuid()), characteristic.getInstanceId(),
new ParcelUuid(characteristic.getUuid()),
characteristic.getWriteType(), AUTHENTICATION_NONE,
characteristic.getValue());
} catch (RemoteException e) {
Log.e(TAG,"",e);
mDeviceBusy = false;
return false;
}
return true;
}
Put a breakpoint inside the method and do debugging. Here are the possible reasons why you get false based on the source code:
The remote BLE device does not have Write or Write with No Response access
Either your service is null or the characteristic value you set is null
Your device is already doing another BLE process with the remote device
In my opinion, most probably the 2nd item is the reason.

Resources