Comments (6)
Hi,
If you wish to record audio, you will need to subscribe to the AudioMediaReceived Event
m_audioSocket.AudioMediaReceived += OnAudioMediaReceived;
This will be raised each time you have a received buffer.
private async void OnAudioMediaReceived(object sender, AudioMediaReceivedEventArgs e)
{
var buffer = e.Buffer;
try
{
if (m_wavFileWriter != null)
{
long length = buffer.Length;
var retrievedBuffer = new byte[length];
Marshal.Copy(buffer.Data, retrievedBuffer, 0, (int) length);
await m_wavFileWriter.EnqueueAsync(retrievedBuffer);
}
}
catch (Exception ex)
{
//log exception
}
finally
{
buffer.Dispose();
}
}
you can use this helper class to write to a wav file, this has dependency on the TPL dataflow nuget and System.Threading
-First you need to create the writer
m_wavFileWriter = new WavFileWriter("WavOut" + DateTime.UtcNow.Ticks + ".wav",
new WavFileSettings());
await m_wavFileWriter.InitializeAsync();
-Then, when the app is done recording call shutdown:
await m_wavFileWriter.ShutdownAsync();
This is the code for the helper class
/// <summary>
/// wav file writer, this class will create a wav file
/// from the received buffers in the smart agents.
/// </summary>
internal class WavFileWriter
{
private BufferBlock<byte[]> m_queueBlock;
private FileStream m_fileStream;
private readonly CancellationTokenSource m_queueCancellationTokenSource;
private readonly SemaphoreSlim m_syncLock = new SemaphoreSlim(1);
private readonly WavFileSettings m_wavFileSettings;
private long m_riffChunkSizePosition;
private long m_dataChunkSizePosition;
public bool IsInitialized { get; private set; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="fileName"></param>
/// <param name="wavFileSettings"></param>
public WavFileWriter(string fileName, WavFileSettings wavFileSettings)
{
m_fileStream = new FileStream(fileName, FileMode.OpenOrCreate,
FileAccess.ReadWrite,
FileShare.None);
m_queueCancellationTokenSource = new CancellationTokenSource();
m_queueBlock = new BufferBlock<byte[]>(new DataflowBlockOptions { CancellationToken = m_queueCancellationTokenSource.Token});
m_wavFileSettings = wavFileSettings;
}
private void WriteRiffChunk(BinaryWriter bw)
{
bw.Write(0x46464952); //'RIFF'
//We remember the riffChunkSizePoistion that we have to update later on stream close
m_riffChunkSizePosition = bw.BaseStream.Position; //Filelength - 8 bytes
bw.Write((int)50); //a 0sec wav file is atleast 58 bytes
bw.Write(0x45564157); //'WAVE'
}
private void WriteFmtChunk(BinaryWriter bw)
{
bw.Write((int)0x20746D66); //'fmt '
bw.Write(16); //16 bytes of format. We produce no 'extra format info'
bw.Write(m_wavFileSettings.CompressionCode); //2bytes
bw.Write(m_wavFileSettings.NumberOfChannels); //2bytes
bw.Write(m_wavFileSettings.SampleRate); //4bytes
bw.Write(m_wavFileSettings.AvgBytesPerSecond); //4bytes
bw.Write((short)2); //alignment
bw.Write((short)16); //significant bits per sample
}
private void WriteFactChunk(BinaryWriter bw)
{
bw.Write((int)0x74636166); //'fact' chunk ID
bw.Write((int)4); //4 byte Fact Chunk size
bw.Write((int)0); //4 byte chunk data.
}
private void WriteDataChunk(BinaryWriter bw)
{
bw.Write(0x61746164); //'data' chunk ID
//We remember the dataChunkPosition that we have to update later on stream close
m_dataChunkSizePosition = bw.BaseStream.Position;
bw.Write((int)0); //initially, we have no data, so we set the chunk size to 0
}
/// <summary>
/// Initializes the consumer of the queue to wait for new items and process them if available
/// </summary>
/// <returns></returns>
public async Task InitializeAsync()
{
if (!IsInitialized)
{
await m_syncLock.WaitAsync();
if (!IsInitialized)
{
IsInitialized = true;
//Initialize the headers
Debug.Assert(m_fileStream != null, "m_fileStream != null");
BinaryWriter bw = new BinaryWriter(m_fileStream);
WriteRiffChunk(bw);
WriteFmtChunk(bw);
WriteFactChunk(bw);
WriteDataChunk(bw);
await Task.Factory.StartNew( () => DequeueAndProcessAsync());
}
m_syncLock.Release();
}
}
/// <summary>
/// Dequeue and process async workitems
/// </summary>
/// <returns></returns>
internal async Task DequeueAndProcessAsync()
{
try
{
while (await m_queueBlock.OutputAvailableAsync(m_queueCancellationTokenSource.Token))
{
var buffer = await m_queueBlock.ReceiveAsync(m_queueCancellationTokenSource.Token);
if (buffer != null)
{
await m_fileStream.WriteAsync(buffer, 0, buffer.Length);
}
this.m_queueCancellationTokenSource.Token.ThrowIfCancellationRequested();
}
}
catch (TaskCanceledException ex)
{
Debug.Write(string.Format("The queue processing task has been cancelled. Exception: {0}", ex));
}
catch (ObjectDisposedException ex)
{
Debug.Write(string.Format("The queue processing task object has been disposed. Exception: {0}", ex));
}
catch (Exception ex)
{
// Catch all other exceptions and log
Debug.Write(string.Format("Caught Exception: {0}", ex));
// Continue processing elements in the queue
await DequeueAndProcessAsync();
}
}
/// <summary>
/// Enqueue a waitable work item
/// </summary>
/// <param name="buffer"></param>
/// <returns></returns>
public async Task EnqueueAsync(byte[] buffer)
{
try
{
await m_queueBlock.SendAsync(buffer, m_queueCancellationTokenSource.Token);
}
catch (TaskCanceledException e)
{
if (m_queueBlock != null)
{
m_queueBlock.Complete();
}
Debug.Write(string.Format("Cannot enqueue because queuing operation has been cancelled. Exception: {0}", e));
}
catch (Exception e)
{
Debug.Write(string.Format("Failed to enqueue: {0}", e));
}
}
/// <summary>
/// ShutDown the queue, this will also cancel current operations
/// </summary>
/// <returns></returns>
public async Task ShutdownAsync()
{
if (IsInitialized)
{
await m_syncLock.WaitAsync();
if (IsInitialized)
{
Debug.Assert(m_queueBlock != null);
// Allow no more processing on the queue
m_queueBlock.Complete();
// Cancel the queue task
m_queueCancellationTokenSource.Cancel();
m_queueCancellationTokenSource.Dispose();
IsInitialized = false;
CloseFileStream();
}
m_syncLock.Release();
}
}
private void CloseFileStream()
{
if (m_fileStream != null)
{
try
{
using(BinaryWriter bw = new BinaryWriter(m_fileStream))
{
//Lets update the riffChunkSize header value
m_fileStream.Seek(m_riffChunkSizePosition, SeekOrigin.Begin);
bw.Write((int)(m_fileStream.Length - 8));
//... and the dataChunksize header value;
m_fileStream.Seek(m_dataChunkSizePosition, SeekOrigin.Begin);
bw.Write((int)(m_fileStream.Length - (m_dataChunkSizePosition + 4)));
}
}
finally
{
m_fileStream.Close();
}
}
}
}
internal class WavFileSettings
{
public short CompressionCode { get; set; }
public short NumberOfChannels { get; set; }
public int SampleRate { get; set; }
public int AvgBytesPerSecond { get; set; }
/// <summary>
/// Default constructor with default PCM 16 mono
/// </summary>
public WavFileSettings()
{
CompressionCode = 1; //PCM
NumberOfChannels = 1; //No Stereo
SampleRate = 16000; //16khz only
AvgBytesPerSecond = 32000;
}
}
from botbuilder-realtimemediacalling.
Are you trying to record within a multiparty group call? Recording the audio of individual participants in a group call is not supported. Please be aware that bots for group calls are currently not supported and such bots will likely stop working soon.
from botbuilder-realtimemediacalling.
@waboum Thanks! I will try this out.
@ssulzer Yes, I am hoping i could record multiparty group call. I currently working with the MeetingScreenshotsBot and it seems that bot is working as it should with group call. From what you've said, does that mean that this sample bot you have (or the feature it has) will be ditched out soon? May I know if this will be supported in the future. Also, bots for Skype For Business??
Thanks,
from botbuilder-realtimemediacalling.
@gfclaveria Upcoming changes will prevent calling and real-time media bots from joining Skype group calls, and unfortunately no timeframe regarding when they will be supported. Calling and real-time media bots will be allowed only in 1-to-1 Skype calls.
No information yet regarding calling and media bots for Skype for Business Online are not supported.
from botbuilder-realtimemediacalling.
@ssulzer Additional question. May we known the reason why will you be removing group calls feature for bot?
from botbuilder-realtimemediacalling.
@gfclaveria currently the bot can record audio and video of any user in the conference which is a privacy concern.
from botbuilder-realtimemediacalling.
Related Issues (20)
- Screen sharing HOT 7
- Speech Recognition not working HOT 3
- Is it possible to use Microsoft translator API ? HOT 1
- HueBot : Error on incoming call
- is this supported by Skype for business? HOT 4
- Can't respond to bot call HOT 1
- Unable to run HueBot locally using ngrok HOT 5
- Support for Microsoft.CognitiveServices.Speech HOT 8
- Unable to call Hue Bot HOT 2
- MS Teams API don't send statusCode when answering to a call HOT 3
- Calling to bot -"you can not talk to the bot just yet..." HOT 3
- Passed stream to AudioVideoFramePlayer and video didn't play HOT 3
- Microsoft.Skype.Bots.Media in .Net Core
- Minimum VM Scale Set size requirements for v1.17.0.39-alpha?
- Unable to use this example
- Not able run this Audio Video Player example
- You can't talk to this Bot just yet. But we are working on it
- Getting started links are broken
- This repo is missing important files HOT 1
- docs link points to itself
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from botbuilder-realtimemediacalling.