Here is my for loop, is my for loop wrong? I have not been doing loops for a very long time so I am still a beginner and I would really appreciate if someone could take a look at my problem.
for (int i = 0; i < tabLayout.getTabCount(); i++) {
TabLayout.Tab tab = tabLayout.getTabAt(i);
if (tab != null) {
tab.setCustomView(mSectionsPagerAdapter.getTabView(i));
}else{
System.out.println("ERROR---TAB IS NULL---ERROR");
}
}
and here is my Count Method and Char
#Override
public int getCount() {
// Show 3 total pages.
return 4;
}
#Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
// return tabTitles[position];
// getDrawable(int i) is deprecated, use getDrawable(int i, Theme theme) for min SDK >=21
// or ContextCompat.getDrawable(Context context, int id) if you want support for older versions.
// Drawable image = context.getResources().getDrawable(iconIds[position], context.getTheme());
// Drawable image = context.getResources().getDrawable(imageResId[position]);
Drawable image = ContextCompat.getDrawable(MainActivity.this, imageResId[position]);
image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
SpannableString sb = new SpannableString(" ");
ImageSpan imageSpan = new ImageSpan(image, ImageSpan.ALIGN_BOTTOM);
sb.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return sb;
}
I have a list picker which is displayed in my phone application page.I have created list picker in starting of class,and i am adding the list picker in the phoneApplicationPage_loaded() method.When the page is launched the first time, ,the scenario works perfectly and its navigates further to second page.When i navigate back to previous page(containing list picker),it shows Invalid Operation Exception occured stating "Element is already the child of another element."
I want to know how to handle these scenarios?
Code is below
namespace My.Design
{
public partial class myclass : PhoneApplicationPage
{
String[] values = null;
ListPicker picker = new ListPicker();
StackPanel sp;
StackPanel mainFrame;
String statementInfo = "";
public myclass()
{
InitializeComponent();
}
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
Debug.WriteLine("Phone Application Page Loaded_>>>>>>");
List<String> source = new List<String>();
displayUI();
}
public void displayUI()
{
Debug.WriteLine("About to display UI in miniStatement");
Debug.WriteLine("<-------------Data--------->");
Debug.WriteLine(statementInfo);
Debug.WriteLine("<-------------Data--------->");
int count = VisualTreeHelper.GetChildrenCount(this);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
UIElement child = (UIElement)VisualTreeHelper.GetChild(this, i);
string childTypeName = child.GetType().ToString();
Debug.WriteLine("Elements in this Child" + childTypeName);
}
}
List<String> source = new List<String>();
String[] allParams = ItemString.Split('#');
source.Add("PleaseSelect");
for (int i = 0; i < allParams.Length; i++)
{
Debug.WriteLine("All Params Length" + allParams[i]);
if (!(allParams[i].Equals("") && (!allParams[i].Equals(null))))
{
if (values != null)
{
Debug.WriteLine("Values length" + values.Length);
values[values.Length] = allParams[i];
}
else
{
Debug.WriteLine("Allparams Length" + allParams[i]);
source.Add(allParams[i]);
}
}
}
//picker = new ListPicker();
this.picker.ItemsSource = source;
mainFrame = new StackPanel();
TextBlock box = new TextBlock();
box.Text = "> DEmoClass";
box.FontSize = 40;
mainFrame.Children.Add(box);
Canvas canvas = new Canvas();
StackPanel sp = new StackPanel();
TextBlock box1 = new TextBlock();
box1.Text = "Number";
box1.HorizontalAlignment = HorizontalAlignment.Center;
box1.FontSize = 40;
SolidColorBrush scb1 = new SolidColorBrush(Colors.Black);
box1.Foreground = scb1;
sp.Children.Add(box1);
picker.Width = 400;
picker.Height = 150;
sp.Children.Add(picker);
Canvas.SetTop(sp, 150);
canvas.Children.Add(sp);
mainFrame.Children.Add(canvas);
this.ContentPanel1.Children.Add(mainFrame);
}
protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)
{
/*
Debug.WriteLine("OnNavigatingFrom>>>.>>MainPage");
if (sp != null)
{
sp.Children.Remove(picker);
}*/
base.OnNavigatingFrom(e);
}
}
}
If you are not intending to update the listpicker after navigating back from the second page add the following line in your Loaded event handler
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
this.Loaded -= PhoneApplicationPage_Loaded;
Debug.WriteLine("Phone Application Page Loaded_>>>>>>");
List<String> source = new List<String>();
displayUI();
}
i don't know why you can not use that case when app resume from tombstoned.
error happened because when you back to your page , loaded event runs again.
by the way,
Application_Activated 's argument can tell you app resumes from tombstoned or not--.
if (e.IsApplicationInstancePreserved)
{
IsTombstoning = false;
}
else
{
IsTombstoning = true;
}
I'm curious why you're creating it in code and not leaving it in XAML? Also the error is coming from the fact that you're attempting to add it twice into a location that can probably only have a single content element. What's the higher level problem you're trying to solve?
I have a screen which call a listfield.
public class Main_AllLatestNews extends MainScreen {
private Database_Webservice webservice;
private String[] title, category, date, imagepath = {"no picture", "no picture", "no picture", "no picture","no picture","no picture","no picture","no picture","no picture", "no picture"};
private int[] newsid;
private List_News newslist;
public Main_AllLatestNews(final boolean needdownload) {
super(USE_ALL_WIDTH);
webservice = new Database_Webservice();
add(new Custom_TopField(this, 0, -1, "", 1, 1));
add(new Custom_BottomField(this, 0));
add(new Custom_HeaderField(Config_GlobalFunction.latest));
if (needdownload){
Main.getUiApplication().pushScreen(
new Custom_LoadingScreen(30));
webservice.UpdateAllCatNews();
}else {
webservice.LoadtodayNews();
newsid = new int[webservice.news.size()];
title = new String[webservice.news.size()];
category = new String[webservice.news.size()];
date = new String[webservice.news.size()];
//imagepath = new String[webservice.news.size()];
for (int i = 0; i < webservice.news.size(); i++) {
newslist = (List_News) webservice.news.elementAt(i);
newsid[i] = newslist.getID();
title[i] = newslist.getNtitle();
category[i] = newslist.getNewCatName();
date[i] = newslist.getNArticalD();
//imagepath[i] = newslist.getImagePath();
}
add(new Custom_ListField(newsid, title, date, category, imagepath, true));
}
}
}
When I add custom_listfield then I get:
Failed to allocate timer 0: no slots left
Here is my listfield
public Custom_ListField(int newsid[], String title[], String date[],
String category[], String imagepath[], boolean islatest) {
super(0, ListField.MULTI_SELECT);
this.newsid = newsid;
setCallback(this);
setBackground(Config_GlobalFunction.loadbackground("background.png"));
this.islatest = islatest;
rows = new Vector();
for (int x = 0; x < title.length; x++) {
TableRowManager row = new TableRowManager();
titlelabel = new Custom_LabelField(title[x],
LabelField.USE_ALL_WIDTH | DrawStyle.LEFT);
titlelabel.setFont(Font.getDefault().derive(Font.BOLD, 23));
row.add(titlelabel);
datelabel = new Custom_LabelField(date[x], DrawStyle.ELLIPSIS
| LabelField.USE_ALL_WIDTH | DrawStyle.LEFT);
datelabel.setFont(Font.getDefault().derive(Font.BOLD, 18));
datelabel.setFontColor(Color.GRAY);
row.add(datelabel);
categorylabel = new Custom_LabelField(category[x],
DrawStyle.ELLIPSIS | LabelField.USE_ALL_WIDTH
| DrawStyle.LEFT);
categorylabel.setFont(Font.getDefault().derive(Font.BOLD, 18));
categorylabel.setFontColor(Color.RED);
row.add(categorylabel);
/*Bitmap imagebitmap = null;
if (!imagepath[x].toString().equals("no picture")) {
imagebitmap = Util_ImageLoader.loadImage(imagepath[x]);
} else {
imagepath[x] = "image_base.png";
imagebitmap = Bitmap.getBitmapResource(imagepath[x]);
}
image = new BitmapField(imagebitmap, Field.FIELD_HCENTER
| Field.FIELD_VCENTER);
row.add(image);*/
//setRowHeight(image.getBitmapHeight() + 10);
setRowHeight(70);
rows.addElement(row);
}
setSize(rows.size());
}
In this list, it will call 10 images or more. First I will check got link send to it else load local images. So the row height must be not same, however, it does not auto set row height for each row but set a same height to all row. I think out of memory because i call too many images? but I call in android also no problem.
This is my imageloader.
public class Util_ImageLoader {
public static Bitmap loadImage(String url) {
HttpConnection connection = null;
InputStream inputStream = null;
EncodedImage bitmap;
byte[] dataArray = null;
try {
// can use this for BlackBerry 5.0+ :
// connection = (HttpConnection) (new
// ConnectionFactory()).getConnection(url).getConnection();
connection = (HttpConnection) Connector
.open(url + Util_GetInternet.getConnParam(),
Connector.READ, true);
int responseCode = connection.getResponseCode();
if (responseCode == HttpConnection.HTTP_OK) {
inputStream = connection.openDataInputStream();
dataArray = IOUtilities.streamToBytes(inputStream);
}
} catch (Exception ex) {
} finally {
try {
inputStream.close();
connection.close();
} catch (Exception e) {
}
}
if (dataArray != null) {
bitmap = EncodedImage.createEncodedImage(dataArray, 0,
dataArray.length);
return bitmap.getBitmap();
} else {
return null;
}
}
}
1) What can I do to reduce the use of memory?
2) How to set different row height? I am set bitmap.getbitmapheight() but different bitmap will have different height.
//Updated//
I am running on simulator 9930 OS 7.0 and 8520 OS 5.0. Both also same result. Real Device cannot run because after signing the key also prompt the warning message try to Secure APi. I am completely commented all the images also same. I did not call neither online nor local image. I think is the data problem?
#AlanLai, can you tell us which device this is being run on, and which OS? Is it a simulator, or real hardware? Why don't you try commenting out the image completely. Don't show any images (network images, or local images). See if you still get the problem. Let's try to narrow down where exactly the code is that's causing your problem. Note: please post the information about which device you're testing on above, in the question, not as a comment response here. Thanks
How about to have only one TableRowManager and every drawRow set values with layout with specific values?
There's a lot of things you can do to reduce memory usage. For one, try to avoid keeping objects in memory longer than you really need them. One way this happens is if you keep member variables in your class, that could really be local variables in a method. Keeping member variables may lead to objects living longer than they need to, preventing the release of the memory they occupy.
Util_ImageLoader
For example, in Util_ImageLoader, you do almost all the work in the constructor. But then, you keep the result around (the Bitmap) in a static member variable (_bmap), which keeps it in memory. I know you do this so that you can call getBitmap(). But, you could change the class to be like this:
public class Util_ImageLoader {
public static Bitmap loadImage(String url) {
HttpConnection connection = null;
InputStream inputStream = null;
EncodedImage bitmap;
byte[] dataArray = null;
try {
// can use this for BlackBerry 5.0+ :
// connection = (HttpConnection) (new ConnectionFactory()).getConnection(url).getConnection();
connection = (HttpConnection) Connector.open(url + Util_GetInternet.getConnParam(), Connector.READ,
true);
int responseCode = connection.getResponseCode();
if (responseCode == HttpConnection.HTTP_OK) {
inputStream = connection.openDataInputStream();
dataArray = IOUtilities.streamToBytes(inputStream);
}
} catch (Exception ex) {
}
finally {
try {
inputStream.close();
connection.close();
} catch (Exception e) {
}
}
if (dataArray != null) {
bitmap = EncodedImage.createEncodedImage(dataArray, 0, dataArray.length);
return bitmap.getBitmap();
} else {
return null;
}
}
}
Because your Util_ImageLoader class doesn't really have any state associated with it, you can probably make it a class with just one static method. The static method does not require you to create an instance of Util_ImageLoader to use it. Just do this:
Bitmap img = Util_ImageLoader.loadImage("http://domain.com/path/image.png");
This allows the image that's loaded to be released as soon as the UI is done with it. The existing code keeps that image in memory for the life of the program.
Also, I replaced your custom code that uses a byte[] buffer, with the useful IOUtilities.streamtoBytes() method. Let the built-in libraries do the work of optimizing for you. Most of the time, they will do a pretty good job of that.
You also had some fixed point scaling code in your Util_ImageLoader class that wasn't doing anything. It was creating a scaled image of the same size as the original. So, I just removed that code. That can only help your memory usage. Image manipulation can be expensive.
Finally, I checked the web server return code (HTTP_OK) before I created any of the large objects needed for this method. If the network request fails, you certainly don't want to waste memory for no reason.
Custom_ListField
Again, you are keeping some objects around, possibly longer than needed. Let's go through your member variables:
private Bitmap bg = Bitmap.getBitmapResource("background.png"),
imagebitmap;
I don't know how many instances of Custom_ListField you will have in your app, but if you are going to assign bg to a constant app resource image, you should at least make it a static member variable, so that if there are 10 instances of Custom_ListField, you will only be keeping one bg variable in memory:
private static Bitmap bg = Bitmap.getBitmapResource("background.png"),
imagebitmap;
But, in your case, I don't think you need to keep that member variable at all. You can simply replace it where it's used, like this:
Background background = BackgroundFactory.createBitmapBackground(Bitmap.getBitmapResource("background.png"));
Then, the imagebitmap member can also be replaced with a local variable:
Bitmap imageBitmap = null;
if (!imagepath[x].toString().equals("no picture")) {
imageBitmap = Util_ImageLoader.loadImage(imagepath[x]);
imageBitmap = loader.getbitmap();
} else {
imagepath[x] = "image_base.png";
imageBitmap = Bitmap.getBitmapResource(imagepath[x]);
}
image = new BitmapField(imageBitmap, Field.FIELD_HCENTER | Field.FIELD_VCENTER);
imageBitmap only needs to be a local variable, not a member variable.
Debugging memory usage usually requires having the whole program, running, and profiling it. With only some of your code, I can't see all the other code that uses it. How many of each class is created is important? Which images are the large ones, and which are small? These are all questions you need to ask yourself to get your memory usage down.
But, hopefully, the general techniques I showed example of above can help you get started.
The problem was the Custom_ListField. This should extends listfield
instead of custom extends manager
public class Custom_ListField extends ListField {
private String[] title, category, date, imagepath;
private int[] newsid, catsid;
private List_News newslist;
private Bitmap imagebitmap[], localimage = Bitmap
.getBitmapResource("image_base.png");
private BrowserField webpage;
private Custom_BrowserFieldListener listener;
private boolean islatest;
private Vector content = null;
private ListCallback callback = null;
private int currentPosition = 0;
public Custom_ListField(Vector content, boolean islatest) {
this.content = content;
this.islatest = islatest;
newsid = new int[content.size()];
title = new String[content.size()];
category = new String[content.size()];
date = new String[content.size()];
imagepath = new String[content.size()];
catsid = new int[content.size()];
imagebitmap = new Bitmap[content.size()];
for (int i = 0; i < content.size(); i++) {
newslist = (List_News) content.elementAt(i);
newsid[i] = newslist.getID();
title[i] = newslist.getNtitle();
category[i] = newslist.getNewCatName();
date[i] = newslist.getNArticalD();
imagepath[i] = newslist.getImagePath();
if (!imagepath[i].toString().equals("no picture")) {
imagebitmap[i] = Util_ImageLoader.loadImage(imagepath[i]);
} else {
imagebitmap[i] = localimage;
}
catsid[i] = newslist.getCatID();
}
initCallbackListening();
this.setRowHeight(localimage.getHeight() + 10);
}
private void initCallbackListening() {
callback = new ListCallback();
this.setCallback(callback);
}
private class ListCallback implements ListFieldCallback {
public ListCallback() {
setBackground(Config_GlobalFunction
.loadbackground("background.png"));
}
public void drawListRow(ListField listField, Graphics graphics,
int index, int y, int width) {
currentPosition = index;
graphics.drawBitmap(
Display.getWidth() - imagebitmap[index].getWidth() - 5,
y + 3, imagebitmap[index].getWidth(),
imagebitmap[index].getHeight(), imagebitmap[index], 0, 0);
graphics.setColor(Color.WHITE);
graphics.drawRect(0, y, width, imagebitmap[index].getHeight() + 10);
graphics.setColor(Color.BLACK);
graphics.setFont(Font.getDefault().derive(Font.BOLD, 20));
graphics.drawText(title[index], 5, y + 3, 0, Display.getWidth()
- imagebitmap[index].getWidth() - 10);
System.out.println(Display.getWidth()
- imagebitmap[index].getWidth() - 10);
graphics.setColor(Color.GRAY);
graphics.setFont(Font.getDefault().derive(Font.BOLD, 15));
graphics.drawText(date[index], 5, y + 6
+ Font.getDefault().getHeight() + 3);
if (islatest) {
graphics.setColor(Color.RED);
graphics.setFont(Font.getDefault().derive(Font.BOLD, 15));
graphics.drawText(category[index], Font.getDefault()
.getAdvance(date[index]) + 3, y + 6
+ Font.getDefault().getHeight() + 3);
}
}
public Object get(ListField listField, int index) {
return content.elementAt(index);
}
public int getPreferredWidth(ListField listField) {
return Display.getWidth();
}
public int indexOfList(ListField listField, String prefix, int start) {
return content.indexOf(prefix, start);
}
}
public int getCurrentPosition() {
return currentPosition;
}
protected boolean navigationClick(int status, int time) {
int index = getCurrentPosition();
if (catsid[index] == 9) {
if (Config_GlobalFunction.isConnected()) {
webpage = new BrowserField();
listener = new Custom_BrowserFieldListener();
webpage.addListener(listener);
MainScreen aboutus = new Menu_Aboutus();
aboutus.add(webpage);
Main.getUiApplication().pushScreen(aboutus);
webpage.requestContent("http://www.orientaldaily.com.my/index.php?option=com_k2&view=item&id="
+ newsid[index] + ":&Itemid=223");
} else
Config_GlobalFunction.Message(Config_GlobalFunction.nowifi, 1);
} else
Main.getUiApplication().pushScreen(
new Main_NewsDetail(newsid[index]));
return true;
}
}
I am successfully able to extract images from a pdf using pdfsharp. The image are of CCITFFaxDecode. But in the tiff image created , the image is getting rotated. Any idea what might be going wrong?
This is the code im using :
byte[] data = xObject.Stream.Value;
Tiff tiff = BitMiracle.LibTiff.Classic.Tiff.Open("D:\\clip_TIFF.tif", "w");
tiff.SetField(TiffTag.IMAGEWIDTH, (uint)(width));
tiff.SetField(TiffTag.IMAGELENGTH, (uint)(height));
tiff.SetField(TiffTag.COMPRESSION, (uint)BitMiracle.LibTiff.Classic.Compression.CCITTFAX4);
tiff.SetField(TiffTag.BITSPERSAMPLE, (uint)(bpp));
tiff.WriteRawStrip(0,data,data.Length);
tiff.Close();
Since the question is still tagged w/iTextSharp might as add some code, even though it doesn't look like you're using the library here. PDF parsing support was added starting in iText[Sharp] 5.
Didn't have an test PDF with the image type you're using, but found one here (see the attachment). Here's a very simple working example in ASP.NET (HTTP handler .ashx) using that test PDF document to get you going:
<%# WebHandler Language="C#" Class="CCITTFaxDecodeExtract" %>
using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.parser;
using Dotnet = System.Drawing.Image;
using System.Drawing.Imaging;
public class CCITTFaxDecodeExtract : IHttpHandler {
public void ProcessRequest (HttpContext context) {
HttpServerUtility Server = context.Server;
HttpResponse Response = context.Response;
string file = Server.MapPath("~/app_data/CCITTFaxDecode.pdf");
PdfReader reader = new PdfReader(file);
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
MyImageRenderListener listener = new MyImageRenderListener();
for (int i = 1; i <= reader.NumberOfPages; i++) {
parser.ProcessContent(i, listener);
}
for (int i = 0; i < listener.Images.Count; ++i) {
string path = Server.MapPath("~/app_data/" + listener.ImageNames[i]);
using (FileStream fs = new FileStream(
path, FileMode.Create, FileAccess.Write
))
{
fs.Write(listener.Images[i], 0, listener.Images[i].Length);
}
}
}
public bool IsReusable { get { return false; } }
/*
* see: TextRenderInfo & RenderListener classes here:
* http://api.itextpdf.com/itext/
*
* and Google "itextsharp extract images"
*/
public class MyImageRenderListener : IRenderListener {
public void RenderText(TextRenderInfo renderInfo) { }
public void BeginTextBlock() { }
public void EndTextBlock() { }
public List<byte[]> Images = new List<byte[]>();
public List<string> ImageNames = new List<string>();
public void RenderImage(ImageRenderInfo renderInfo) {
PdfImageObject image = renderInfo.GetImage();
PdfName filter = image.Get(PdfName.FILTER) as PdfName;
if (filter == null) {
PdfArray pa = (PdfArray) image.Get(PdfName.FILTER);
for (int i = 0; i < pa.Size; ++i) {
filter = (PdfName) pa[i];
}
}
if (PdfName.CCITTFAXDECODE.Equals(filter)) {
using (Dotnet dotnetImg = image.GetDrawingImage()) {
if (dotnetImg != null) {
ImageNames.Add(string.Format(
"{0}.tiff", renderInfo.GetRef().Number)
);
using (MemoryStream ms = new MemoryStream()) {
dotnetImg.Save(
ms, ImageFormat.Tiff);
Images.Add(ms.ToArray());
}
}
}
}
}
}
}
If the image(s) is/are being rotated, see this thread on the iText mailing list; perhaps some of the pages in the PDF document have been rotated.
By the by this is the complete code which is extracting the image from the pdf, but rotating it. Sorry about the length of the code.
PdfDocument document = PdfReader.Open("D:\\Sample.pdf");
PdfDictionary resources =document.pages.Elements.GetDictionary("/Resources");
PdfDictionary xObjects = resources.Elements.GetDictionary("/XObject");
if (xObjects != null)
{
ICollection<PdfItem> items = xObjects.Elements.Values;
// Iterate references to external objects
foreach (PdfItem item in items)
{
PdfReference reference = item as PdfReference;
if (reference != null)
{
PdfDictionary xObject = reference.Value as PdfDictionary;
// Is external object an image?
if (xObject != null && xObject.Elements.GetString("/Subtype") == "/Image")
{
string filter = xObject.Elements.GetName("/Filter");
if (filter.Equals("/CCITTFaxDecode"))
{
int width = xObject.Elements.GetInteger(PdfImage.Keys.Width);
int height = xObject.Elements.GetInteger(PdfImage.Keys.Height);
int bpp = xObject.Elements.GetInteger(PdfImage.Keys.BitsPerComponent);
byte[] data = xObject.Stream.Value;
Tiff tiff = BitMiracle.LibTiff.Classic.Tiff.Open("D:\\sample.tif", "w");
tiff.SetField(TiffTag.IMAGEWIDTH, (uint)(width));
tiff.SetField(TiffTag.IMAGELENGTH, (uint)(height));
tiff.SetField(TiffTag.COMPRESSION, (uint)BitMiracle.LibTiff.Classic.Compression.CCITTFAX4);
tiff.SetField(TiffTag.BITSPERSAMPLE, (uint)(bpp));
tiff.SetField(TiffTag.STRIPOFFSETS, 187);
tiff.WriteRawStrip(0,data,data.Length);
tiff.Close();
}
}
}
}
}
I'm using NAudio (but it applies to reading directly) to capture microphone wave data. It seems that if my app is busy it drops/skips some input data from the mic.
I've set the reading thread to top priority, but I'm doing heavy calculations in several other thread at the same time.
Is there a way to read data lossless?
(Or is it lossless, and my bug elsewhere?)
When I was making a similar app and had a similar problem, it turned out that I needed a buffer that can hold at least 3 seconds of data. Try to increase the buffer to 10 seconds of data and if it doesn't solve your problem then there are more issues. If it works try decreasing the buffer size until it works properly
EDIT: Here a quick & dirty managed dx recording for you to try.
public class BMSRecordingEventArgs : EventArgs
{
byte[] data;
bool endRec;
public BMSRecordingEventArgs(byte[] data, bool endRec)
{
this.data = data;
this.endRec = endRec;
}
public byte[] Data
{
get { return data; }
}
public bool EndRec
{
get { return endRec; }
}
}
public class AudioRecorder
{
public delegate void DataReceivedHandler(object sender, BMSRecordingEventArgs e);
public event DataReceivedHandler DataReceivedHandle;
public const int CAPTURE_BUFFER_SIZE = 32000;
DXS.Capture dxsCapDev;
DXS.CaptureBuffer dxsCapBuffer;
DXS.CaptureBufferDescription dxsCapBufferDesc;
System.Threading.Thread thrdCapturingThread;
DXS.BufferPositionNotify[] dxsBpna;
private volatile bool StopRec;
System.Threading.ManualResetEvent mreStillRunning = new System.Threading.ManualResetEvent(false);
DXS.BufferPositionNotify dxsBPNHalf;
DXS.BufferPositionNotify dxsBPNFull;
DXS.Notify Notify;
System.Threading.AutoResetEvent ARE;
public AudioRecorder(Guid DeviceGuid,DXS.WaveFormat wfWaveFormat,DXS.CaptureEffectDescription[] dxsCapEffectDesc)
{
dxsCapDev = new Microsoft.DirectX.DirectSound.Capture(DeviceGuid);
dxsCapBufferDesc = new Microsoft.DirectX.DirectSound.CaptureBufferDescription();
dxsCapBufferDesc.BufferBytes = CAPTURE_BUFFER_SIZE;
dxsCapBufferDesc.Format = wfWaveFormat;
dxsCapBufferDesc.WaveMapped = true;
dxsCapBufferDesc.CaptureEffectDescription = dxsCapEffectDesc;
dxsCapBufferDesc.ControlEffects = true;
dxsCapBuffer = new Microsoft.DirectX.DirectSound.CaptureBuffer(dxsCapBufferDesc, dxsCapDev);
ARE = new System.Threading.AutoResetEvent(false);
dxsBPNHalf = new Microsoft.DirectX.DirectSound.BufferPositionNotify();
dxsBPNFull = new Microsoft.DirectX.DirectSound.BufferPositionNotify();
dxsBPNHalf.Offset = CAPTURE_BUFFER_SIZE / 2 - 1;
dxsBPNFull.Offset = CAPTURE_BUFFER_SIZE-1;
dxsBPNFull.EventNotifyHandle = ARE.SafeWaitHandle.DangerousGetHandle();
dxsBPNHalf.EventNotifyHandle = ARE.SafeWaitHandle.DangerousGetHandle();
dxsBpna = new Microsoft.DirectX.DirectSound.BufferPositionNotify[2];
dxsBpna[0] = dxsBPNHalf;
dxsBpna[1] = dxsBPNFull;
Notify = new Microsoft.DirectX.DirectSound.Notify(dxsCapBuffer);
Notify.SetNotificationPositions(dxsBpna);
}
public void StartRecording()
{
if (thrdCapturingThread != null)
throw new Exception("Already Recording !");
StopRec = false;
thrdCapturingThread = new System.Threading.Thread(Record);
thrdCapturingThread.Start();
}
private void Record()
{
DataReceivedHandler drh2 = DataReceivedHandle;
dxsCapBuffer.Start(true);
byte[] TempBaf = new byte[CAPTURE_BUFFER_SIZE / 2];
int StartingOffset = 0;
while (dxsCapBuffer.Capturing && !StopRec)
{
ARE.WaitOne(-1,false);
StartingOffset %= CAPTURE_BUFFER_SIZE;
TempBaf = (byte[])dxsCapBuffer.Read(StartingOffset, typeof(byte), Microsoft.DirectX.DirectSound.LockFlag.FromWriteCursor, CAPTURE_BUFFER_SIZE / 2);
StartingOffset += TempBaf.Length;
if (drh2 != null)
drh2(this, new BMSRecordingEventArgs(TempBaf, false));
}
dxsCapBuffer.Stop();
if (drh2 != null)
drh2(this, new BMSRecordingEventArgs(TempBaf, true));
mreStillRunning.Set();
}
public void StopRecording()
{
StopRec = true;
mreStillRunning.WaitOne(-1,false);
thrdCapturingThread = null;
}
}