#pragma once
/*
* Copyright (C) 2005-2017 Team KODI
* http://kodi.tv
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kodi; see the file COPYING. If not, see
* .
*
*/
#include "AddonBase.h"
#ifdef BUILD_KODI_ADDON
#include "AEChannelData.h"
#else
#include "cores/AudioEngine/Utils/AEChannelData.h"
#endif
//==============================================================================
///
/// \defgroup cpp_kodi_audioengine Interface - kodi::audioengine
/// \ingroup cpp
/// @brief **Audio engine functions**
///
///
/// It has the header \ref AudioEngine.h "#include " be included
/// to enjoy it.
///
//------------------------------------------------------------------------------
//==============================================================================
///
/// \defgroup cpp_kodi_audioengine_Defs Definitions, structures and enumerators
/// \ingroup cpp_kodi_audioengine
/// @brief **Library definition values**
///
//------------------------------------------------------------------------------
extern "C"
{
//============================================================================
/// \ingroup cpp_kodi_audioengine_Defs
/// @brief Bit options to pass to CAddonAEStream
///
typedef enum AudioEngineStreamOptions
{
/// force resample even if rates match
AUDIO_STREAM_FORCE_RESAMPLE = 1 << 0,
/// create the stream paused
AUDIO_STREAM_PAUSED = 1 << 1,
/// autostart the stream when enough data is buffered
AUDIO_STREAM_AUTOSTART = 1 << 2,
/// if this option is set the ADSP-System is bypassed and the raw stream
/// will be passed through IAESink
AUDIO_STREAM_BYPASS_ADSP = 1 << 3
} AudioEngineStreamOptions;
//----------------------------------------------------------------------------
//============================================================================
/// \defgroup cpp_kodi_audioengine_Defs_AudioEngineFormat struct AudioEngineFormat
/// \ingroup cpp_kodi_audioengine_Defs
/// @brief The audio format structure that fully defines a stream's audio
/// information
///
//@{
struct AudioEngineFormat
{
/// The stream's data format (eg, AE_FMT_S16LE)
enum AEDataFormat m_dataFormat;
/// The stream's sample rate (eg, 48000)
unsigned int m_sampleRate;
/// The encoded streams sample rate if a bitstream, otherwise undefined
unsigned int m_encodedRate;
/// The amount of used speaker channels
unsigned int m_channelCount;
/// The stream's channel layout
enum AEChannel m_channels[AE_CH_MAX];
/// The number of frames per period
unsigned int m_frames;
/// The size of one frame in bytes
unsigned int m_frameSize;
AudioEngineFormat()
{
m_dataFormat = AE_FMT_INVALID;
m_sampleRate = 0;
m_encodedRate = 0;
m_frames = 0;
m_frameSize = 0;
m_channelCount = 0;
for (unsigned int ch = 0; ch < AE_CH_MAX; ++ch)
{
m_channels[ch] = AE_CH_MAX;
}
}
/// Function to compare the format structure with another
bool compareFormat(const AudioEngineFormat *fmt)
{
if (!fmt)
{
return false;
}
if (m_dataFormat != fmt->m_dataFormat ||
m_sampleRate != fmt->m_sampleRate ||
m_encodedRate != fmt->m_encodedRate ||
m_frames != fmt->m_frames ||
m_frameSize != fmt->m_frameSize ||
m_channelCount != fmt->m_channelCount)
{
return false;
}
for (unsigned int ch = 0; ch < AE_CH_MAX; ++ch)
{
if (fmt->m_channels[ch] != m_channels[ch])
{
return false;
}
}
return true;
}
};
//@}
//----------------------------------------------------------------------------
/* A stream handle pointer, which is only used internally by the addon stream handle */
typedef void AEStreamHandle;
/*
* Function address structure, not need to visible on dev kit doxygen
* documentation
*/
typedef struct AddonToKodiFuncTable_kodi_audioengine
{
AEStreamHandle* (*make_stream)(void *kodiBase, AudioEngineFormat* format, unsigned int options);
void (*free_stream)(void *kodiBase, AEStreamHandle *stream);
bool (*get_current_sink_format)(void *kodiBase, AudioEngineFormat* sink_format);
// Audio Engine Stream definitions
unsigned int (*aestream_get_space)(void *kodiBase, AEStreamHandle *handle);
unsigned int (*aestream_add_data)(void *kodiBase, AEStreamHandle *handle, uint8_t* const *data,
unsigned int offset, unsigned int frames, double pts);
double (*aestream_get_delay)(void *kodiBase, AEStreamHandle *handle);
bool (*aestream_is_buffering)(void *kodiBase, AEStreamHandle *handle);
double (*aestream_get_cache_time)(void *kodiBase, AEStreamHandle *handle);
double (*aestream_get_cache_total)(void *kodiBase, AEStreamHandle *handle);
void (*aestream_pause)(void *kodiBase, AEStreamHandle *handle);
void (*aestream_resume)(void *kodiBase, AEStreamHandle *handle);
void (*aestream_drain)(void *kodiBase, AEStreamHandle *handle, bool wait);
bool (*aestream_is_draining)(void *kodiBase, AEStreamHandle *handle);
bool (*aestream_is_drained)(void *kodiBase, AEStreamHandle *handle);
void (*aestream_flush)(void *kodiBase, AEStreamHandle *handle);
float (*aestream_get_volume)(void *kodiBase, AEStreamHandle *handle);
void (*aestream_set_volume)(void *kodiBase, AEStreamHandle *handle, float volume);
float (*aestream_get_amplification)(void *kodiBase, AEStreamHandle *handle);
void (*aestream_set_amplification)(void *kodiBase, AEStreamHandle *handle, float amplify);
unsigned int (*aestream_get_frame_size)(void *kodiBase, AEStreamHandle *handle);
unsigned int (*aestream_get_channel_count)(void *kodiBase, AEStreamHandle *handle);
unsigned int (*aestream_get_sample_rate)(void *kodiBase, AEStreamHandle *handle);
AEDataFormat (*aestream_get_data_format)(void *kodiBase, AEStreamHandle *handle);
double (*aestream_get_resample_ratio)(void *kodiBase, AEStreamHandle *handle);
void (*aestream_set_resample_ratio)(void *kodiBase, AEStreamHandle *handle, double ratio);
} AddonToKodiFuncTable_kodi_audioengine;
} /* extern "C" */
namespace kodi
{
namespace audioengine
{
//============================================================================
///
/// \defgroup cpp_kodi_audioengine_CAddonAEStream class CAddonAEStream
/// \ingroup cpp_kodi_audioengine
/// @brief **Audio Engine Stream Class**
///
///
/// It has the header \ref AudioEngine.h "#include " be
/// included to enjoy it.
///
//----------------------------------------------------------------------------
class CAddonAEStream
{
public:
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Contructs new class to an Kodi IAEStream in the format specified.
///
/// @param[in] format The data format the incoming audio will be in
/// (e.g. \ref AE_FMT_S16LE)
/// @param[in] options [opt] A bit field of stream options (see: enum \ref AudioEngineStreamOptions)
///
///
/// ------------------------------------------------------------------------
///
/// **Audio engine format information:**
/// @code
/// /*
/// * Audio engine format information
/// *
/// * Only as example shown here! See always the original structure on related header.
/// */
/// typedef struct AudioEngineFormat
/// {
/// enum AEDataFormat m_dataFormat; /* The stream's data format (eg, AE_FMT_S16LE) */
/// unsigned int m_sampleRate; /* The stream's sample rate (eg, 48000) */
/// unsigned int m_encodedRate; /* The encoded streams sample rate if a bitstream, otherwise undefined */
/// unsigned int m_channelCount; /* The amount of used speaker channels */
/// enum AEChannel m_channels[AE_CH_MAX]; /* The stream's channel layout */
/// unsigned int m_frames; /* The number of frames per period */
/// unsigned int m_frameSamples; /* The number of samples in one frame */
/// unsigned int m_frameSize; /* The size of one frame in bytes */
///
/// /* Function to compare the format structure with another */
/// bool compareFormat(const AudioEngineFormat *fmt);
/// } AudioEngineFormat;
/// @endcode
///
/// ------------------------------------------------------------------------
///
/// **Bit options to pass to CAELib_Stream (on Kodi by IAE::MakeStream)**
///
/// | enum AEStreamOptions | Value: | Description:
/// |----------------------------:|:------:|:-----------------------------------
/// | AUDIO_STREAM_FORCE_RESAMPLE | 1 << 0 | Force resample even if rates match
/// | AUDIO_STREAM_PAUSED | 1 << 1 | Create the stream paused
/// | AUDIO_STREAM_AUTOSTART | 1 << 2 | Autostart the stream when enough data is buffered
/// | AUDIO_STREAM_BYPASS_ADSP | 1 << 3 | if this option is set the ADSP-System is bypassed and the raw stream will be passed through IAESink.
///
///
/// ------------------------------------------------------------------------
///
/// **Example:**
/// ~~~~~~~~~~~~~{.cpp}
///
/// #include
///
/// using namespace kodi::audioengine;
///
/// ...
///
/// AudioEngineFormat format;
/// format.m_dataFormat = AE_FMT_FLOAT;
/// format.m_channelCount = 2;
/// format.m_channels[0] = AE_CH_FL;
/// format.m_channels[1] = AE_CH_FR;
/// format.m_channels[2] = AE_CH_NULL;
/// format.m_sampleRate = 48000;
/// format.m_frameSize = sizeof(float)*format.m_channelCount;
/// format.m_frames = 512;
/// CAddonAEStream* stream = new CAddonAEStream(format, AE_STREAM_AUTOSTART | AE_STREAM_BYPASS_ADSP);
///
/// ~~~~~~~~~~~~~
///
CAddonAEStream(AudioEngineFormat format, unsigned int options = 0)
: m_kodiBase(::kodi::addon::CAddonBase::m_interface->toKodi->kodiBase),
m_cb(::kodi::addon::CAddonBase::m_interface->toKodi->kodi_audioengine)
{
m_StreamHandle = m_cb->make_stream(m_kodiBase, &format, options);
if (m_StreamHandle == nullptr)
{
kodi::Log(ADDON_LOG_FATAL, "CAddonAEStream: make_stream failed!");
}
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Class destructor
///
~CAddonAEStream()
{
if (m_StreamHandle)
{
m_cb->free_stream(m_kodiBase, m_StreamHandle);
m_StreamHandle = nullptr;
}
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Returns the amount of space available in the stream
///
/// @return The number of bytes AddData will consume
///
unsigned int GetSpace()
{
return m_cb->aestream_get_space(m_kodiBase, m_StreamHandle);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Add planar or interleaved PCM data to the stream
///
/// @param[in] data array of pointers to the planes
/// @param[in] offset to frame in frames
/// @param[in] frames number of frames
/// @param[in] pts presentation timestamp
/// @return The number of frames consumed
///
unsigned int AddData(uint8_t* const *data, unsigned int offset, unsigned int frames, double pts = 0.0)
{
return m_cb->aestream_add_data(m_kodiBase, m_StreamHandle, data, offset, frames, pts);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Returns the time in seconds that it will take for the next added
/// packet to be heard from the speakers.
///
/// @return seconds
///
double GetDelay()
{
return m_cb->aestream_get_delay(m_kodiBase, m_StreamHandle);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Returns if the stream is buffering
///
/// @return True if the stream is buffering
///
bool IsBuffering()
{
return m_cb->aestream_is_buffering(m_kodiBase, m_StreamHandle);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Returns the time in seconds of the stream's cached audio samples.
/// Engine buffers excluded.
///
/// @return seconds
///
double GetCacheTime()
{
return m_cb->aestream_get_cache_time(m_kodiBase, m_StreamHandle);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Returns the total time in seconds of the cache
///
/// @return seconds
///
double GetCacheTotal()
{
return m_cb->aestream_get_cache_total(m_kodiBase, m_StreamHandle);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Pauses the stream playback
///
void Pause()
{
return m_cb->aestream_pause(m_kodiBase, m_StreamHandle);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Resumes the stream after pausing
///
void Resume()
{
return m_cb->aestream_resume(m_kodiBase, m_StreamHandle);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Start draining the stream
///
/// @param[in] wait [opt] Wait until drain is finished if set to
/// true, otherwise it returns direct
///
/// @note Once called AddData will not consume more data.
///
void Drain(bool wait = true)
{
return m_cb->aestream_drain(m_kodiBase, m_StreamHandle, wait);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Returns true if the is stream draining
///
bool IsDraining()
{
return m_cb->aestream_is_draining(m_kodiBase, m_StreamHandle);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Returns true if the is stream has finished draining
///
bool IsDrained()
{
return m_cb->aestream_is_drained(m_kodiBase, m_StreamHandle);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Flush all buffers dropping the audio data
///
void Flush()
{
return m_cb->aestream_flush(m_kodiBase, m_StreamHandle);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Return the stream's current volume level
///
/// @return The volume level between 0.0 and 1.0
///
float GetVolume()
{
return m_cb->aestream_get_volume(m_kodiBase, m_StreamHandle);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Set the stream's volume level
///
/// @param[in] volume The new volume level between 0.0 and 1.0
///
void SetVolume(float volume)
{
return m_cb->aestream_set_volume(m_kodiBase, m_StreamHandle, volume);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Gets the stream's volume amplification in linear units.
///
/// @return The volume amplification factor between 1.0 and 1000.0
///
float GetAmplification()
{
return m_cb->aestream_get_amplification(m_kodiBase, m_StreamHandle);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Sets the stream's volume amplification in linear units.
///
/// @param[in] amplify The volume amplification factor between
/// 1.0 and 1000.0
///
void SetAmplification(float amplify)
{
return m_cb->aestream_set_amplification(m_kodiBase, m_StreamHandle, amplify);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Returns the size of one audio frame in bytes (channelCount * resolution)
///
/// @return The size in bytes of one frame
///
unsigned int GetFrameSize() const
{
return m_cb->aestream_get_frame_size(m_kodiBase, m_StreamHandle);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Returns the number of channels the stream is configured to accept
///
/// @return The channel count
///
unsigned int GetChannelCount() const
{
return m_cb->aestream_get_channel_count(m_kodiBase, m_StreamHandle);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Returns the stream's sample rate, if the stream is using a dynamic
/// sample rate, this value will NOT reflect any changes made by calls to
/// SetResampleRatio()
///
/// @return The stream's sample rate (eg, 48000)
///
unsigned int GetSampleRate() const
{
return m_cb->aestream_get_sample_rate(m_kodiBase, m_StreamHandle);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Return the data format the stream has been configured with
///
/// @return The stream's data format (eg, AUDIOENGINE_FMT_S16LE)
///
AEDataFormat GetDataFormat() const
{
return m_cb->aestream_get_data_format(m_kodiBase, m_StreamHandle);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Return the resample ratio
///
/// @note This will return an undefined value if the stream is not resampling
///
/// @return the current resample ratio or undefined if the stream is not resampling
///
double GetResampleRatio()
{
return m_cb->aestream_get_resample_ratio(m_kodiBase, m_StreamHandle);
}
//--------------------------------------------------------------------------
//==========================================================================
/// @ingroup cpp_kodi_audioengine_CAddonAEStream
/// @brief Sets the resample ratio
///
/// @note This function may return false if the stream is not resampling, if
/// you wish to use this be sure to set the AESTREAM_FORCE_RESAMPLE option
///
/// @param[in] ratio the new sample rate ratio, calculated by
/// ((double)desiredRate / (double)GetSampleRate())
///
void SetResampleRatio(double ratio)
{
m_cb->aestream_set_resample_ratio(m_kodiBase, m_StreamHandle, ratio);
}
//--------------------------------------------------------------------------
private:
void* m_kodiBase;
AddonToKodiFuncTable_kodi_audioengine* m_cb;
AEStreamHandle *m_StreamHandle;
};
//============================================================================
/// @ingroup cpp_kodi_audioengine
/// @brief Get the current sink data format
///
/// @param[in] format Current sink data format. For more details see AudioEngineFormat.
/// @return Returns true on success, else false.
///
inline bool GetCurrentSinkFormat(AudioEngineFormat &format)
{
using namespace kodi::addon;
return CAddonBase::m_interface->toKodi->kodi_audioengine->get_current_sink_format(CAddonBase::m_interface->toKodi->kodiBase, &format);
}
//----------------------------------------------------------------------------
} /* audioengine */
} /* kodi */