最近做的项目需要用到C#的录音功能,在网上找了不少资源,大部分都是说使用DX来录音,下载下来demo大部分都是缺少东西,也确实是没有弄明白。下面介绍一个简单的录音方式,这也是翻阅了大神的博客了解到的,在这里进行了一些本地化的扩展。
在这个操作类下公开了两个方法和两个事件,方法分别是开始录音和结束录音,在结束录音时,可以传递一个参数作为取消录音的控制,传入true后将不会保存出文件。
这两个事件,一个时实时反馈进度的事件,可以使你实时控制进度条的显示,一个是录制完成的事件,即当你控制录制结束时,就会产生该事件,这个时间返回了录制的时间(采用进1法),录制的语音文件地址,是否是被取消的状态。事件的参数类这里没有给出,可以根据传递的参数自行添加或修改。
/// <summary>
/// 语音录制控制类
/// </summary>
public class RecordingAudio
{
/// <summary>
/// 录制完成事件,该事件只会在UI线程上执行
/// </summary>
public event EventHandler<RecordingFinishEventArgs> OnRecordingFinish;
/// <summary>
/// 录制进度事件,该事件只会在UI线程上执行
/// </summary>
public event EventHandler<RecordingProgressEventArgs> OnRecordingProgress;
private int duration = 0;
private Timer timer;
/// <summary>
/// 接收的主线程控件,使跨线程的操作回归到主线程上产生事件
/// </summary>
private Control control;
/// <summary>
/// 锁
/// </summary>
private object _obj = new object();
public RecordingAudio(Control control)
{
this.control = control;
this.timer = new Timer(200);
this.timer.Elapsed += timer_Tick;
}
/// <summary>
/// 获取当前是否是正在录制状态
/// </summary>
public bool IsRecordingAudio { get; private set; }
[DllImport("winmm.dll", EntryPoint = "mciSendString", CharSet = CharSet.Auto)]
public static extern int mciSendString(
string lpstrCommand,
string lpstrReturnString,
int uReturnLength,
int hwndCallback
);
/// <summary>
/// 更新进度
/// </summary>
/// <param name="p">进度值</param>
private void UpdateProgress(double p)
{
if (OnRecordingProgress != null)
{
this.control.Dispatcher.Invoke(new Action(() =>
{
OnRecordingProgress(this, new RecordingProgressEventArgs(p));
}));
}
}
/// <summary>
/// 录制完成
/// </summary>
private void RecordingFinish(int t, string path, bool isCancle)
{
if (OnRecordingFinish != null)
{
this.control.Dispatcher.Invoke(new Action(() =>
{
OnRecordingFinish(this, new RecordingFinishEventArgs(t, path, isCancle));
}));
}
}
/// <summary>
/// 开始录制
/// </summary>
public void Start()
{
lock (_obj)
{
if (IsRecordingAudio) return;
mciSendString("set wave bitpersample 8", "", 0, 0);
mciSendString("set wave samplespersec 20000", "", 0, 0);
mciSendString("set wave channels 2", "", 0, 0);
mciSendString("set wave format tag pcm", "", 0, 0);
mciSendString("open new type WAVEAudio alias movie", "", 0, 0);
mciSendString("record movie", "", 0, 0);
duration = 0;
timer.Enabled = true;
IsRecordingAudio = true;
UpdateProgress(duration);
}
}
private void timer_Tick(object sender, ElapsedEventArgs e)
{
duration++;
UpdateProgress(duration * 200 / 1000.0);
}
/// <summary>
/// 停止录制
/// </summary>
/// <param name="isCancle">是否是取消录制,默认为false</param>
/// <returns></returns>
public void Stop(bool isCancle = false)
{
lock (_obj)
{
if (!IsRecordingAudio) return;
timer.Enabled = false;
FileUtils.CheckAndCreateFolder();
string wavPath = "resource/" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".wav";
string mp3Path = "resource/" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".mp3";
string basePath = AppDomain.CurrentDomain.BaseDirectory;
mciSendString("stop movie", "", 0, 0);
if (!isCancle)
{
mciSendString("save movie " + wavPath, "", 0, 0);
}
mciSendString("close movie", "", 0, 0);
IsRecordingAudio = false;
int s = duration * 200;
RecordingFinish(s % 1000 == 0 ? s / 1000 : s / 1000 + 1, basePath + mp3Path, isCancle);
}
}
}
<Grid x:Name="soundGrid" Visibility="Visible" Margin="0,0,0,125" Height="35" VerticalAlignment="Bottom" Background="#FFECECEC">
<!--<ProgressBar x:Name="soundProgress" Maximum="55" Margin="60,10,205,10" Background="#FFBDBDBD" BorderBrush="{x:Null}"/>-->
<local:ProgressBarControl x:Name="soundProgress" Maximum="55" ProgressBackground="#FFECECEC" ProgressColor="#FF7DFF41"/>
<Label Content="语音录制中" HorizontalAlignment="Left" Margin="10,5,0,0" VerticalAlignment="Top"/>
<Button x:Name="enterSendSound" Cursor="Hand" Margin="0,5,70,0" Background="#FF75BDFF" VerticalAlignment="Top" HorizontalAlignment="Right" Width="50" Click="enterSendSound_Click">
<Button.Template>
<ControlTemplate>
<Border Background="#FF75BDFF" CornerRadius="5,5,5,5">
<Label Content="确定" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" />
</Border>
</ControlTemplate>
</Button.Template>
</Button>
<Button x:Name="cancelSendSound" Cursor="Hand" Margin="0,5,10,0" Background="#FFFFB924" VerticalAlignment="Top" HorizontalAlignment="Right" Width="50" Click="cancelSendSound_Click">
<Button.Template>
<ControlTemplate>
<Border Background="#FFFFB924" CornerRadius="5,5,5,5">
<Label Content="取消" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" />
</Border>
</ControlTemplate>
</Button.Template>
</Button>
<!--<Label x:Name="soundTip" Content="55s/55s" Margin="0,5,140,0" VerticalAlignment="Top" HorizontalAlignment="Right" Width="60"/>-->
</Grid>
只是有一个录制的进度。
ProgressBarControl 自定义控件
XAML:
<Grid>
<Rectangle x:Name="progressBG" Fill="White" StrokeThickness="0" />
<Rectangle x:Name="progressValue" HorizontalAlignment="Left" Width="0" StrokeThickness="0" />
<Label x:Name="progressTip" Content="" Padding="0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
代码:
/// <summary>
/// ProgressBarControl.xaml 的交互逻辑
/// </summary>
public partial class ProgressBarControl : UserControl
{
public ProgressBarControl()
{
InitializeComponent();
}
/// <summary>
/// 获取或设置进度条的背景色
/// </summary>
[Description("获取或设置进度条的背景色")]
public System.Windows.Media.Brush ProgressBackground
{
get { return progressBG.Fill; }
set { progressBG.Fill = value; }
}
/// <summary>
/// 获取或设置进度条的边框色
/// </summary>
[Description("获取或设置进度条的边框色")]
public System.Windows.Media.Brush ProgressStroke
{
get { return progressBG.Stroke; }
set { progressBG.Stroke = value; }
}
/// <summary>
/// 获取或设置进度条的边框粗细
/// </summary>
[Description("获取或设置进度条的边框粗细")]
public double ProgressStrokeThickness
{
get { return progressBG.StrokeThickness; }
set { progressBG.StrokeThickness = value; }
}
/// <summary>
/// 获取或设置进度条的进度色
/// </summary>
[Description("获取或设置进度条的进度色")]
public System.Windows.Media.Brush ProgressColor
{
get { return progressValue.Fill; }
set { progressValue.Fill = value; }
}
/// <summary>
/// 获取或设置进度条提示信息
/// </summary>
[Description("获取或设置进度条提示信息")]
public string HintProgress
{
get { return progressTip.Content.ToString(); }
set { progressTip.Content = value; }
}
/// <summary>
/// 获取或设置进度条提示信息文字大小
/// </summary>
[Description("获取或设置进度条提示信息文字大小")]
public double HintFontSize
{
get { return progressTip.FontSize; }
set { progressTip.FontSize = value; }
}
/// <summary>
/// 获取或设置进度条提示信息字体颜色
/// </summary>
[Description("获取或设置进度条提示信息字体颜色")]
public System.Windows.Media.Brush HintForeground
{
get { return progressTip.Foreground; }
set { progressTip.Foreground = value; }
}
private double _Maximum = 100.0;
/// <summary>
/// 获取或设置进度条的最大进度值,默认值为100
/// </summary>
/// <exception cref="InvalidOperationException">进度值不可小于等于零</exception>
[Description("获取或设置进度条的最大进度值")]
public double Maximum
{
get { return _Maximum; }
set
{
if (value <= 0)
throw new InvalidOperationException("进度值不可小于等于零");
_Maximum = value;
}
}
private double _Value;
/// <summary>
/// 获取或设置进度条的进度值
/// </summary>
/// <exception cref="InvalidOperationException">进度值不能小于0且不能大于进度最大值</exception>
[Description("获取或设置进度条的进度值")]
public double Value
{
get { return _Value; }
set
{
if (value < 0)
throw new InvalidOperationException("进度值不可小于零");
else if(value > _Maximum)
throw new InvalidOperationException("进度值不可大于最大进度值");
_Value = value;
this.progressValue.Width = (_Value / _Maximum) * this.progressBG.ActualWidth;
}
}
}
这里录制完成时wav文件,某些需求可能是需要装换为MP3格式,针对音频装换也有开源的代码。