Windows Phone – Audio recorder

Audio recorder is a typical application of a mobile phone. Man can use it to record audio from microphone and use it for his ring phone, store audio note or record evidence of crimes as in Hollywood films, etc… Therefore today I decide to write a small audio recorder which should run on any mobile phone using windows phone OS. The application is very small but helpful. You can get source code in the end of this post.

The core of this application is class Microphone of Microsoft.Xna.Framework.Audio which can be used by referencing to Microsoft.Xna.Framework. By declaring a microphone device, setting some predefined features, then I can handle the event BufferReady to record sound section of 1 second from microphone into an array of byte and append it to memory stream.

Microphone m_micDevice = Microphone.Default;

private void btnStart_Click(object sender, RoutedEventArgs e)
{
	...
	m_micDevice.BufferDuration = TimeSpan.FromMilliseconds(1000);
	m_baBuffer = new byte[m_micDevice.GetSampleSizeInBytes(m_micDevice.BufferDuration)];
	m_micDevice.BufferReady +=new EventHandler(m_Microphone_BufferReady);
	m_micDevice.Start();
}

void m_Microphone_BufferReady(object sender, EventArgs e)
{
	m_micDevice.GetData(m_baBuffer);
	...
	m_msAudio.Write(m_baBuffer,0, m_baBuffer.Length);
}

When the users click on Stop button, they will be asked for saving the memory stream to IsolateStorageFile

if (txtAudio.Text != "")
{
	IsolatedStorageFile isfData = IsolatedStorageFile.GetUserStoreForApplication();
	string strSource = txtAudio.Text;
	int nIndex = 0;
	while (isfData.FileExists(txtAudio.Text))
	{
		strSource = txtAudio.Text + nIndex.ToString().PadLeft(2, '0') + ".wav";
	}

	IsolatedStorageFileStream isfStream = new IsolatedStorageFileStream(txtAudio.Text, FileMode.Create, IsolatedStorageFile.GetUserStoreForApplication());
	isfStream.Write(m_msAudio.ToArray(), 0, m_msAudio.ToArray().Length);
	isfStream.Close();
}

So it’s very simple to write an audio recorder in Windows Phone 7. In my recorder I add some data visualizer to notify the user that the recording is going on. This visualizer uses first 100 value of audio data and shows them in a bar chart. These values will vary continuously and make visualizer animating.

<phoneNavigation:PhoneApplicationPage.Resources>
	<DataTemplate x:Key="template">
		<StackPanel Orientation="Horizontal" VerticalAlignment="Bottom">
			<Rectangle Height="{Binding}" Width="5" Fill="Blue" />
			<Rectangle Width="2" />
		</StackPanel>
	</DataTemplate>
</phoneNavigation:PhoneApplicationPage.Resources>

<ItemsControl x:Name="icBar" ItemsSource="{Binding Path=AudioData}"
	ItemTemplate="{StaticResource template}" Margin="0,6,0,114">
	<ItemsControl.ItemsPanel>
		<ItemsPanelTemplate>
			<StackPanel Orientation="Horizontal"/>
		</ItemsPanelTemplate>
	</ItemsControl.ItemsPanel>
</ItemsControl>

As you can see in order to update record progressing on GUI, I used data binding for ItemsSource property of ItemsControl and update this source each time when the event BufferReady is fired.

void m_Microphone_BufferReady(object sender, EventArgs e)
{
	...
	this.Dispatcher.BeginInvoke(() =>
		{
			vm.LoadAudioData(m_baBuffer);
			...
		}
		);
	...
}

The complete source code of this audio recorder you can download here “Windows Phone Audio Recorder“. If the archive is corrupted, see source code here
http://hintdesk.com/Web/Source/Windows%20Phone%20Audio%20Recorder/

Windows Phone – Passing arguments between pages and Input Scope

On my serie of posts for developing on Windows Phone, today I would like to illustrate how I can pass arguments to page when navigating to it and apply input scope to reduce the input panel for specific input data format. Let’s start with passing argument to page before opening it. If you are Windows Form/WPF developer, you may use a property to get data for form before opening or loading it. This data will be provided to some pre-processing tasks before showing form to user. For example

Form1 f1 = new Form1();
f1.DataToBeSet = "Hihihaha";
f1.Show();

However in Silverlight or Windows Phone, there is no Show() or ShowDialog() function anymore. I can only navigate between page like following.

NavigationService.Navigate(new Uri("/WebPage.xaml", UriKind.Relative));

So then how can I pass argument for page before showing it to users. It is pretty simple, you just need to add some query arguments in Uri and get them back when the new page is loading as following

//On calling Page
NavigationService.Navigate(new Uri("/BrowsePage.xaml?RSSSource="+strSource, UriKind.Relative));
...
//On the BrowsePage side
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
	try
	{
		...
			string strRSSSource = "";
			NavigationContext.QueryString.TryGetValue("RSSSource", out strRSSSource);
			vmDatabase.GetRssItems(strRSSSource);
		...
	}
	catch (Exception ex)
	{
		MessageBox.Show(ex.Message);
	}
}

So you can see how I can pass argument RSSSource to BrowserPage.xaml.

InputScope
The next section in this post I would like to discuss about InputScope and input panel. In windows phone the Software Input Panel can not be customized anymore. Although you can not customize the input panel but you can adjust its view according to input context. For example if you mark a TextBox as requiring a TelephoneNumber you will get a numerical keypad . There are a number of different contexts supported which you can read here http://msdn.microsoft.com/en-us/library/system.windows.input.inputscopenamevalue%28VS.96%29.aspx . Some of typical InputScopeNameValue are listed below
– Password
– TelephoneNumber
– EmailNameOrAddress
– Maps
– NameOrPhoneNumber
– Url

To apply the input context for the text box, you just need to set the InputScope property to one of listed valued in link above to get a matched panel.

<TextBox InputScope="Url" Text="http://vnexpress.net/RSS/GL/trang-chu.rss" x:Name="txtURL" Margin="0,50,0,0" Height="71" VerticalAlignment="Top">

The differences of input panel between with and without setting InputScope you can see in example below.

With InputScope Without InputScope

Update 07.04.2010: Remove some quotations cause of copyright.

C#, WPF – Webservice Part I

When I studied WCF Services and wrote some examples for training, I would like to make some basic review about Web Services therefore today I decide to write some simple examples working with Web Services. I know that there are a lot of examples with Web Services on internet but I want to write my own one so that I can use it later. Anyway reading and understanding my own example and explanation is faster than reading from the other one. Let’s start with step by step instructions. This example I took from book “Datenbank-Programmierung mit Visual C# 2005” with some modifications. At the end of this example I will have a running Web Service and a client get its data to show and edit.

1. Open Visual Studio and create new project type ASP.NET Web Service called “OrderService”.
2. Copy and move file Company.mdb as our database into App_Data.
3. In Web.config file, edit “connectionStrings” and add our connection to our database

<connectionStrings>
	<add name="DataConnectionString" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\Company.mdb;Persist Security Info = True" providerName="System.Data.Oledb"/>
</connectionStrings>

4. Remember set your project only running on x86 platform because OleDB does not support 64 bit OS. Add two web methods in our service to get data and let data be updated to database. The code looks little ugly but it works ^^.

private string strConnection = WebConfigurationManager.ConnectionStrings["DataConnectionString"].ToString();
[WebMethod]
public DataSet GetOrders(int CustomerNr, DateTime From, DateTime Till)
{
	DbProviderFactory provider = DbProviderFactories.GetFactory("System.Data.OleDb");
	DbConnection conn = provider.CreateConnection();
	conn.ConnectionString = strConnection;
	DbCommand cmd = provider.CreateCommand();
	cmd.Connection = conn;
	cmd.CommandText = "SELECT * FROM Orders WHERE CustomerNr = ? AND (EntranceDate BETWEEN ? AND ?)";
	DbParameter dbPar = cmd.CreateParameter();
	dbPar.ParameterName = "@CustomerNr";
	dbPar.DbType = DbType.Int32;
	dbPar.Value = CustomerNr;
	cmd.Parameters.Add(dbPar);

	dbPar = cmd.CreateParameter();
	dbPar.ParameterName = "@From";
	dbPar.DbType = DbType.Date;
	dbPar.Value = From;
	cmd.Parameters.Add(dbPar);

	dbPar = cmd.CreateParameter();
	dbPar.ParameterName = "@Till";
	dbPar.DbType = DbType.Date;
	dbPar.Value = Till;
	cmd.Parameters.Add(dbPar);

	DbDataAdapter da = provider.CreateDataAdapter();
	da.MissingSchemaAction = MissingSchemaAction.AddWithKey;
	da.SelectCommand = cmd;
	DataSet dsOrder = new DataSet("OrderDS");
	conn.Open();
	da.Fill(dsOrder,"Orders");
	conn.Close();
	return dsOrder;
}

[WebMethod]
public void SetOrders(ref DataSet OrderDS)
{
	DbProviderFactory provider = DbProviderFactories.GetFactory("System.Data.OleDb");
	DbConnection conn = provider.CreateConnection();
	conn.ConnectionString = strConnection;
	DbCommand cmd = provider.CreateCommand();
	cmd.Connection = conn;
	cmd.CommandText = "SELECT * FROM Orders";
	DbDataAdapter da = provider.CreateDataAdapter();
	da.SelectCommand = cmd;
	da.ContinueUpdateOnError = true;
	DbCommandBuilder cb = provider.CreateCommandBuilder();
	cb.DataAdapter = da;
	conn.Open();
	da.Update(OrderDS.Tables["Orders"]);
	conn.Close();
}

5. Let’s compile and run our service. If everything goes, I’ll get the last result looks like following. Let’s test our GetOrders Web method.

6. Let’s add new project to our solution as our client. The new project is WPF Application “OrderClient”.
7. Use Microsoft Expression Blend 3 to design user interface as shown above. The user interface contain some labels, 3 buttons, 2 date picker and a data grid.
8. Right click on “OrderClient” project and “Add service reference”. On new opening dialog, click on Discover and choose Service in Solution and choose “OrdersService”.

9. Add handler to button click to load data and save changed data to our database.

private void btnLoadOrders_Click(object sender, System.Windows.RoutedEventArgs e)
{
	// TODO: Add event handler implementation here.
	try
	{
		int nCustNr = Convert.ToInt32(txtCustomer.Text);
		if (m_ServiceType == CallServiceTypes.ASYNCHRON)
		{
			OrdersService.GetOrdersCompleted += new EventHandler<OrderClient.OrdersServiceReference.GetOrdersCompletedEventArgs>(OrdersService_GetOrdersCompleted);
			OrdersService.GetOrdersAsync(nCustNr, dpFrom.DisplayDate, dpTill.DisplayDate);
		}
		else
		{
			m_dsOrders = OrdersService.GetOrders(nCustNr, dpFrom.DisplayDate, dpTill.DisplayDate);
			dgData.ItemsSource = m_dsOrders.Tables["Orders"].DefaultView;
		}
		//dgData.DataContext = dsTemp.Tables["Orders"];

	}
	catch (Exception ex)
	{
		MessageBox.Show(ex.Message);
	}
}

10. As you can see in the code above I use asynchronous and synchronous to get data. When using asynchronous method, for any reasons if the web service is not available, the method will not last until Timeout error raises but it will response immediately so that we do not wait. To use asynchronous method, we must configure our referenced service to auto create asynchronous operations.

The complete source code of example you can download here “Order Service

WCF – Publish WCF Services in IIS 7 step by step for dummies

Today I would like a post about deploying WCF in IIS to help you avoiding nightmare from error given back by IIS 7 during installation. In the end of this post, you can host a wcf service in your localhost and call it like following

1. Install IIS 7 on your computer. Control Panel –> Programs and Features –> Turn Windows features on or off –> Navigate to “Internet Information Services” –> Select these options, then click on.

Continue reading WCF – Publish WCF Services in IIS 7 step by step for dummies