/*
* Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Linq;
using System.Threading.Tasks;
using Tizen.System;
using static Tizen.Multimedia.Interop.Radio;
namespace Tizen.Multimedia
{
///
/// Provides a means for using the radio feature.
///
public class Radio : IDisposable
{
private Interop.RadioHandle _handle;
private const string FeatureFmRadio = "http://tizen.org/feature/fmradio";
///
/// Initializes a new instance of the Radio class.
///
/// The radio feature is not supported.
public Radio()
{
ValidateFeatureSupported(FeatureFmRadio);
Create(out _handle);
try
{
SetScanCompletedCb(_handle, ScanCompleteCallback).ThrowIfFailed("Failed to initialize radio");
SetInterruptedCb(_handle, InterruptedCallback).ThrowIfFailed("Failed to initialize radio");
}
catch (Exception)
{
_handle.Dispose();
throw;
}
}
private Interop.RadioHandle Handle
{
get
{
if (_disposed)
{
throw new ObjectDisposedException(GetType().Name);
}
return _handle;
}
}
///
/// Occurs when the radio scanning information is updated.
///
public event EventHandler ScanUpdated;
///
/// Occurs when the radio scanning stops.
///
public event EventHandler ScanStopped;
///
/// Occurs when the radio scanning is completed.
///
public event EventHandler ScanCompleted;
///
/// Occurs when the radio is interrupted.
///
public event EventHandler Interrupted;
///
/// Gets the current state of the radio.
///
public RadioState State
{
get
{
RadioState state;
GetState(Handle, out state);
return state;
}
}
///
/// Gets or sets the radio frequency in the range of 87500 ~ 108000 kHz.
///
///
/// is less than of .\n
/// - or - \n
/// is greater than of .\n
///
public int Frequency
{
get
{
int value = 0;
GetFrequency(Handle, out value).ThrowIfFailed("Failed to get frequency");
return value;
}
set
{
if (value < FrequencyRange.Min || value > FrequencyRange.Max)
{
throw new ArgumentOutOfRangeException(nameof(Frequency), value, "Frequency must be within FrequencyRange.");
}
SetFrequency(Handle, value).ThrowIfFailed("Failed to set frequency");
}
}
///
/// Gets the current signal strength in the range of -128 ~ 128 dBm.
///
public int SignalStrength
{
get
{
int value = 0;
GetSignalStrength(Handle, out value).ThrowIfFailed("Failed to get signal strength");
return value;
}
}
///
/// Gets the value indicating if the radio is muted.
///
///
/// true if the radio is muted; otherwise, false.
/// The default is false.
///
public bool IsMuted
{
get
{
bool value;
GetMuted(Handle, out value).ThrowIfFailed("Failed to get the mute state");
return value;
}
set
{
SetMute(Handle, value).ThrowIfFailed("Failed to set the mute state");
}
}
///
/// Gets the channel spacing for the current region.
///
public int ChannelSpacing
{
get
{
int value;
GetChannelSpacing(Handle, out value).ThrowIfFailed("Failed to get channel spacing");
return value;
}
}
///
/// Gets or sets the radio volume level.
///
/// Valid volume range is from 0 to 1.0(100%), inclusive.
/// The default is 1.0.
///
/// is less than zero.\n
/// - or -\n
/// is greater than 1.0.
///
public float Volume
{
get
{
float value;
GetVolume(Handle, out value).ThrowIfFailed("Failed to get volume level.");
return value;
}
set
{
if (value < 0F || 1.0F < value)
{
throw new ArgumentOutOfRangeException(nameof(value), value,
$"Valid volume range is 0 <= value <= 1.0, but got { value }.");
}
SetVolume(Handle, value).ThrowIfFailed("Failed to set volume level");
}
}
///
/// Gets the frequency for the region in the range of 87500 ~ 108000 kHz.
///
public Range FrequencyRange
{
get
{
int min, max;
GetFrequencyRange(Handle, out min, out max).ThrowIfFailed("Failed to get frequency range");
return new Range(min, max);
}
}
///
/// Starts the radio.
///
/// The radio must be in the state.
/// The radio is not in the valid state.
public void Start()
{
ValidateRadioState(RadioState.Ready);
Interop.Radio.Start(Handle).ThrowIfFailed("Failed to start radio");
}
///
/// Stops the radio.
///
/// The radio must be in the state.
/// The radio is not in the valid state.
public void Stop()
{
ValidateRadioState(RadioState.Playing);
Interop.Radio.Stop(Handle).ThrowIfFailed("Failed to stop radio");
}
///
/// Starts the radio scanning and triggers the ScanInformationUpdated event when the scan information is updated.
///
/// The radio must be in the or state.
/// The radio is not in the valid state.
///
///
public void StartScan()
{
ValidateRadioState(RadioState.Ready, RadioState.Playing);
ScanStart(Handle, ScanUpdatedCallback);
}
///
/// Stops the radio scanning.
///
/// The radio must be in the state.
/// The radio is not in the valid state.
///
public void StopScan()
{
ValidateRadioState(RadioState.Scanning);
ScanStop(Handle, ScanStoppedCallback);
}
///
/// Seeks up the effective frequency of the radio.
///
///
/// A task that represents the asynchronous seeking operation.
/// The result value is the current frequency in the range of 87500 ~ 108000 kHz.
/// It can be -1 if the seeking operation has failed.
///
/// The radio must be in the state.
/// The radio is not in the valid state.
public async Task SeekUpAsync()
{
ValidateRadioState(RadioState.Playing);
TaskCompletionSource tcs = new TaskCompletionSource();
SeekCompletedCallback callback = (currentFrequency, _) =>
{
tcs.TrySetResult(currentFrequency);
};
SeekUp(Handle, callback);
return await tcs.Task;
}
///
/// Seeks down the effective frequency of the radio.
///
///
/// A task that represents the asynchronous seeking operation.
/// The result value is the current frequency in the range of 87500 ~ 108000 kHz.
/// It can be -1 if the seeking operation has failed.
///
/// The radio must be in the state.
/// The radio is not in the valid state.
public async Task SeekDownAsync()
{
ValidateRadioState(RadioState.Playing);
TaskCompletionSource tcs = new TaskCompletionSource();
SeekCompletedCallback callback = (currentFrequency, _) =>
{
tcs.TrySetResult(currentFrequency);
};
SeekDown(Handle, callback);
return await tcs.Task;
}
private void ValidateFeatureSupported(string featurePath)
{
bool supported = false;
Information.TryGetValue(featurePath, out supported);
if (supported == false)
{
throw new NotSupportedException($"The feature({featurePath}) is not supported.");
}
}
private void ScanUpdatedCallback(int frequency, IntPtr data)
{
ScanUpdated?.Invoke(this, new ScanUpdatedEventArgs(frequency));
}
private void ScanStoppedCallback(IntPtr data)
{
ScanStopped?.Invoke(this, EventArgs.Empty);
}
private void ScanCompleteCallback(IntPtr data)
{
ScanCompleted?.Invoke(this, EventArgs.Empty);
}
private void InterruptedCallback(RadioInterruptedReason reason, IntPtr data)
{
Interrupted?.Invoke(this, new RadioInterruptedEventArgs(reason));
}
private void ValidateRadioState(params RadioState[] required)
{
RadioState curState = State;
if (required.Contains(curState) == false)
{
throw new InvalidOperationException($"{curState} is not valid state.");
}
}
#region IDisposable Support
private bool _disposed = false;
///
/// Releases the resources used by the Radio.
///
///
/// true to release both managed and unmanaged resources; false to release only unmanaged resources.
///
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (_handle != null)
{
_handle.Dispose();
}
_disposed = true;
}
}
///
/// Releases all resources used by the object.
///
public void Dispose()
{
Dispose(true);
}
#endregion
}
}