2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 using System.Runtime.InteropServices;
20 namespace Tizen.Multimedia
23 /// Provides the ability to directly manage the system audio input devices.
25 /// <remarks>The recorder privilege(http://tizen.org/privilege/recorder) is required.</remarks>
26 public abstract class AudioCaptureBase : IDisposable
28 public readonly int MinSampleRate = 8000;
29 public readonly int MaxSampleRate = 48000;
31 internal IntPtr _handle = IntPtr.Zero;
33 private AudioIOState _state = AudioIOState.Idle;
35 internal AudioCaptureBase(int sampleRate, AudioChannel channel, AudioSampleType sampleType)
37 if (sampleRate < MinSampleRate || MaxSampleRate < sampleRate)
39 throw new ArgumentOutOfRangeException(nameof(sampleRate), sampleRate,
40 $"Valid sampleRate range is { MinSampleRate } <= x <= { MaxSampleRate }.");
43 ValidationUtil.ValidateEnum(typeof(AudioChannel), channel);
44 ValidationUtil.ValidateEnum(typeof(AudioSampleType), sampleType);
46 SampleRate = sampleRate;
48 SampleType = sampleType;
50 AudioIOUtil.ThrowIfError(
51 Interop.AudioIO.AudioInput.Create(SampleRate, (int)Channel, (int)SampleType, out _handle));
53 RegisterStateChangedCallback();
62 /// Occurs when the state of the AudioCapture is changed.
64 public event EventHandler<AudioIOStateChangedEventArgs> StateChanged;
66 private Interop.AudioIO.AudioStateChangedCallback _stateChangedCallback;
68 private void RegisterStateChangedCallback()
70 _stateChangedCallback = (IntPtr handle, int previous, int current, bool byPolicy, IntPtr _) =>
72 _state = (AudioIOState)current;
74 StateChanged?.Invoke(this,
75 new AudioIOStateChangedEventArgs((AudioIOState)previous, _state, byPolicy));
78 AudioIOUtil.ThrowIfError(
79 Interop.AudioIO.AudioInput.SetStateChangedCallback(_handle, _stateChangedCallback, IntPtr.Zero));
82 #region Dispose support
83 private bool _isDisposed = false;
88 GC.SuppressFinalize(this);
91 protected virtual void Dispose(bool disposing)
98 if (_handle != IntPtr.Zero)
100 if (_state != AudioIOState.Idle)
111 Interop.AudioIO.AudioInput.Destroy(_handle);
112 _handle = IntPtr.Zero;
117 internal void ValidateNotDisposed()
121 throw new ObjectDisposedException(GetType().Name);
126 internal void ValidateState(params AudioIOState[] desiredStates)
128 ValidateNotDisposed();
130 AudioIOUtil.ValidateState(_state, desiredStates);
134 /// Gets the sample rate of the audio input data stream.
136 public int SampleRate { get; }
139 /// Gets the channel type of the audio input data stream.
141 public AudioChannel Channel { get; }
144 /// Gets the sample type of the audio input data stream.
146 public AudioSampleType SampleType { get; }
149 /// Gets the size to be allocated for the audio input buffer.
151 /// <exception cref="ObjectDisposedException">The AudioPlayback has already been disposed.</exception>
152 public int GetBufferSize()
155 AudioIOUtil.ThrowIfError(Interop.AudioIO.AudioInput.GetBufferSize(_handle, out size));
160 /// Prepares the AudioCapture for reading audio data by starting buffering of audio data from the device.
162 /// <exception cref="InvalidOperationException">
163 /// Operation failed due to internal error.
164 /// <para>-or-</para>
165 /// The current state is not <see cref="AudioIOState.Idle"/>.
167 /// <seealso cref="Unprepare"/>
168 public void Prepare()
170 ValidateState(AudioIOState.Idle);
172 AudioIOUtil.ThrowIfError(Interop.AudioIO.AudioInput.Prepare(_handle),
173 "Failed to prepare the AudioCapture");
177 /// Unprepares the AudioCapture.
179 /// <exception cref="InvalidOperationException">
180 /// Operation failed due to internal error.
181 /// <para>-or-</para>
182 /// The current state is <see cref="AudioIOState.Idle"/>.
184 /// <seealso cref="Prepare"/>
185 public void Unprepare()
187 ValidateState(AudioIOState.Running, AudioIOState.Paused);
189 AudioIOUtil.ThrowIfError(Interop.AudioIO.AudioInput.Unprepare(_handle),
190 "Failed to unprepare the AudioCapture");
194 /// Pauses buffering of audio data from the device.
196 /// <exception cref="InvalidOperationException">
197 /// The current state is <see cref="AudioState.Idle"/>.
198 /// <para>-or-</para>
199 /// The method is called in the <see cref="AsyncAudioCapture.DataAvailable"/> event handler.
201 /// <seealso cref="Resume"/>
204 if (_state == AudioIOState.Paused)
208 ValidateState(AudioIOState.Running);
210 AudioIOUtil.ThrowIfError(Interop.AudioIO.AudioInput.Pause(_handle));
213 /// Resumes buffering audio data from the device.
215 /// <exception cref="InvalidOperationException">
216 /// The current state is <see cref="AudioState.Idle"/>.
217 /// <para>-or-</para>
218 /// The method is called in the <see cref="AsyncAudioCapture.DataAvailable"/> event handler.
220 /// <seealso cref="Pause"/>
223 if (_state == AudioIOState.Running)
227 ValidateState(AudioIOState.Paused);
229 AudioIOUtil.ThrowIfError(Interop.AudioIO.AudioInput.Resume(_handle));
232 /// Flushes and discards buffered audio data from the input stream.
234 /// <exception cref="InvalidOperationException">The current state is <see cref="AudioState.Idle"/>.</exception>
237 ValidateState(AudioIOState.Running, AudioIOState.Paused);
239 int ret = Interop.AudioIO.AudioInput.Flush(_handle);
241 MultimediaDebug.AssertNoError(ret);
245 /// Sets the sound stream information to the audio input.
247 /// <param name="streamPolicy">The <see cref="AudioStreamPolicy"/> to apply for the AudioCapture.</param>
248 /// <exception cref="ArgumentNullException"><paramref name="streamPolicy"/> is null.</exception>
249 /// <exception cref="ObjectDisposedException"><paramref name="streamPolicy"/> has already been disposed.</exception>
250 /// <exception cref="NotSupportedException"><paramref name="streamPolicy"/> is not supported.</exception>
251 /// <exception cref="ArgumentException">Not able to retrieve information from <paramref name="streamPolicy"/>.</exception>
252 public void ApplyStreamPolicy(AudioStreamPolicy streamPolicy)
254 if (streamPolicy == null)
256 throw new ArgumentNullException(nameof(streamPolicy));
259 if (streamPolicy.Handle == IntPtr.Zero)
261 throw new ObjectDisposedException(nameof(streamPolicy));
264 ValidateNotDisposed();
266 AudioIOUtil.ThrowIfError(Interop.AudioIO.AudioInput.SetStreamInfo(_handle, streamPolicy.Handle));
271 /// Provides the ability to record audio from system audio input devices in synchronous way.
273 /// <remarks>The recorder privilege(http://tizen.org/privilege/recorder) is required.</remarks>
274 public class AudioCapture : AudioCaptureBase
277 /// Initializes a new instance of the AudioCapture class with the specified sample rate, channel and sampleType.
279 /// <param name="sampleRate">The audio sample rate.(8000 ~ 48000Hz)</param>
280 /// <param name="channel">The audio channel type.</param>
281 /// <param name="sampleType">The audio sample type.</param>
282 /// <exception cref="ArgumentOutOfRangeException">
283 /// <paramref name="sampleRate"/> is less than <see cref="MinSampleRate"/>.
284 /// <para>-or-</para>
285 /// <paramref name="sampleRate"/> is greater than <see cref="MaxSampleRate"/>.
287 /// <exception cref="ArgumentException">
288 /// The value of <paramref name="channel"/> is invalid.
289 /// <para>-or-</para>
290 /// The value of <paramref name="sampleType"/> is invalid.
292 /// <exception cref="InvalidOperationException">The required privilege is not specified.</exception>
293 /// <exception cref="NotSupportedException">The system does not support microphone.</exception>
294 public AudioCapture(int sampleRate, AudioChannel channel, AudioSampleType sampleType)
295 : base(sampleRate, channel, sampleType)
300 /// Reads audio data from the audio input buffer.
302 /// <param name="length"></param>
303 /// <returns>The buffer of audio data receiving an input</returns>
304 /// <exception cref="InvalidOperationException">The current state is not <see cref="AudioIOState.Running"/>.</exception>
305 /// <exception cref="ArgumentOutOfRangeException"><paramref name="length"/> is equal to or less than zero.</exception>
306 public byte[] Read(int length)
310 throw new ArgumentOutOfRangeException(nameof(length), length,
311 $"{ nameof(length) } can't be equal to or less than zero.");
313 ValidateState(AudioIOState.Running);
315 byte[] buffer = new byte[length];
317 AudioIOUtil.ThrowIfError(Interop.AudioIO.AudioInput.Read(_handle, buffer, length),
325 /// Provides the ability to record audio from system audio input devices in asynchronous way.
327 /// <remarks>The recorder privilege(http://tizen.org/privilege/recorder) is required.</remarks>
328 public class AsyncAudioCapture : AudioCaptureBase
332 /// Occurs when audio data is available.
334 public event EventHandler<AudioDataAvailableEventArgs> DataAvailable;
337 /// Initializes a new instance of the AsyncAudioCapture class with the specified sample rate, channel and sampleType.
339 /// <param name="sampleRate">The audio sample rate.(8000 ~ 48000Hz)</param>
340 /// <param name="channel">The audio channel type.</param>
341 /// <param name="sampleType">The audio sample type.</param>
342 /// <exception cref="ArgumentOutOfRangeException">
343 /// <paramref name="sampleRate"/> is less than <see cref="MinSampleRate"/>.
344 /// <para>-or-</para>
345 /// <paramref name="sampleRate"/> is greater than <see cref="MaxSampleRate"/>.
347 /// <exception cref="ArgumentException">
348 /// The value of <paramref name="channel"/> is invalid.
349 /// <para>-or-</para>
350 /// The value of <paramref name="sampleType"/> is invalid.
352 /// <exception cref="InvalidOperationException">The required privilege is not specified.</exception>
353 /// <exception cref="NotSupportedException">The system does not support microphone.</exception>
354 public AsyncAudioCapture(int sampleRate, AudioChannel channel, AudioSampleType sampleType)
355 : base(sampleRate, channel, sampleType)
357 _streamCallback = (IntPtr handle, uint length, IntPtr _) => { OnInputDataAvailable(handle, length); };
359 AudioIOUtil.ThrowIfError(
360 Interop.AudioIO.AudioInput.SetStreamCallback(_handle, _streamCallback, IntPtr.Zero),
361 $"Failed to initialize a { nameof(AsyncAudioCapture) }");
364 private Interop.AudioIO.AudioStreamCallback _streamCallback;
366 private void OnInputDataAvailable(IntPtr handle, uint length)
373 IntPtr ptr = IntPtr.Zero;
376 AudioIOUtil.ThrowIfError(Interop.AudioIO.AudioInput.Peek(_handle, out ptr, ref length));
378 byte[] buffer = new byte[length];
379 Marshal.Copy(ptr, buffer, 0, (int)length);
381 Interop.AudioIO.AudioInput.Drop(_handle);
383 DataAvailable?.Invoke(this, new AudioDataAvailableEventArgs(buffer));
387 Log.Error(nameof(AsyncAudioCapture), e.Message);