Go to the documentation of this file.
6 #include <QAndroidJniEnvironment>
12 #define LOC QString("AOSLES: ")
14 #define OPENSLES_BUFFERS 10
15 #define OPENSLES_BUFLEN 10
18 #define POSITIONUPDATEPERIOD 40
21 #define CHECK_OPENSL_ERROR(msg) \
22 if (result != SL_RESULT_SUCCESS) \
24 VBERROR(QString("Open Error: (%1)").arg(result)); \
29 #define CHECK_OPENSL_START_ERROR(msg) \
30 if (result != SL_RESULT_SUCCESS) \
32 VBERROR(QString("Start Error: (%1)").arg(result)); \
38 #define Destroy(a) (*(a))->Destroy(a);
39 #define SetPlayState(a, b) (*(a))->SetPlayState(a, b)
40 #define RegisterCallback(a, b, c) (*(a))->RegisterCallback(a, b, c)
41 #define GetInterface(a, b, c) (*(a))->GetInterface(a, b, c)
42 #define Realize(a, b) (*(a))->Realize(a, b)
43 #define CreateOutputMix(a, b, c, d, e) (*(a))->CreateOutputMix(a, b, c, d, e)
44 #define CreateAudioPlayer(a, b, c, d, e, f, g) \
45 (*(a))->CreateAudioPlayer(a, b, c, d, e, f, g)
46 #define Enqueue(a, b, c) (*(a))->Enqueue(a, b, c)
47 #define Clear(a) (*(a))->Clear(a)
48 #define GetState(a, b) (*(a))->GetState(a, b)
49 #define SetPositionUpdatePeriod(a, b) (*(a))->SetPositionUpdatePeriod(a, b)
50 #define SetVolumeLevel(a, b) (*(a))->SetVolumeLevel(a, b)
51 #define GetVolumeLevel(a, b) (*(a))->GetVolumeLevel(a, b)
52 #define SetMute(a, b) (*(a))->SetMute(a, b)
59 QAndroidJniEnvironment jniEnv;
60 jclass cls = jniEnv->FindClass(
"android/media/AudioTrack");
61 jmethodID method = jniEnv->GetStaticMethodID (cls,
"getNativeOutputSampleRate",
"(I)I");
62 int sample_rate = jniEnv->CallStaticIntMethod (cls, method, 3);
66 return QAndroidJniObject::CallStaticMethodInt(
"android/media/AudioTrack",
"getNativeOutputSampleRate",
"(I)I", 3);
71 int GetNativeOutputFramesPerBuffer(
void)
73 QAndroidJniObject activity = QtAndroid::androidActivity();
75 QAndroidJniObject audioManager = activity.CallObjectMethod(
"getSystemService",
"", );
76 jstring sValue = audioManager.CallMethod<jstring>(
"getProperty", PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
78 return QAndroidJniObject::CallStaticMethodInt(
"android/media/AudioManager",
"getProperty",
"(I)I", 3);
89 VBERROR(
"Error: Failed to load libOpenSLES");
97 VBERROR(
"Error: Failed to load symbol slCreateEngine");
102 #define OPENSL_DLSYM(dest, name) \
104 const SLInterfaceID *sym = (const SLInterfaceID *)dlsym(m_so_handle, "SL_IID_" name); \
105 if (sym == nullptr) \
107 LOG(VB_GENERAL, LOG_ERR, "AOOSLES Error: Failed to load symbol SL_IID_" name); \
134 const SLboolean req1[] = { SL_BOOLEAN_FALSE };
150 SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
151 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
155 SLDataFormat_PCM format_pcm;
156 format_pcm.formatType = SL_DATAFORMAT_PCM;
157 format_pcm.numChannels = 2;
158 format_pcm.samplesPerSec = ((SLuint32)
m_sampleRate * 1000) ;
159 format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
162 case FORMAT_U8: format_pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_8;
break;
163 case FORMAT_S16: format_pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
break;
165 case FORMAT_S24LSB: format_pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_24;
break;
167 format_pcm.endianness = SL_BYTEORDER_BIGENDIAN;
168 format_pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_24;
170 case FORMAT_S32: format_pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_32;
break;
177 format_pcm.containerSize = format_pcm.bitsPerSample;
178 format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
180 SLDataSource audioSrc = {&loc_bufq, &format_pcm};
183 SLDataLocator_OutputMix loc_outmix = {
184 SL_DATALOCATOR_OUTPUTMIX,
187 SLDataSink audioSnk = {&loc_outmix,
nullptr};
191 static const SLboolean req2[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
195 &audioSnk,
sizeof(ids2) /
sizeof(*ids2),
204 result = SL_RESULT_UNKNOWN_ERROR;
206 if (result != SL_RESULT_SUCCESS) {
209 format_pcm.samplesPerSec = ((SLuint32) 48000 * 1000) ;
211 &audioSnk,
sizeof(ids2) /
sizeof(*ids2),
349 #if 0 // 32-bit floating point (AC3) is not supported on all platforms.
376 VBAUDIO(QString(
"Buffering %1 fragments of %2 bytes each, total: %3 bytes")
406 SLAndroidSimpleBufferQueueState st;
408 if (res != SL_RESULT_SUCCESS) {
409 VBERROR(QString(
"Could not query buffer queue state in %1 (%2)").
arg(__func__).
arg(res));
412 VBAUDIO(QString(
"Num Queued %1").
arg(st.count));
423 if (numBufferesQueued < 0)
449 if (r != SL_RESULT_SUCCESS)
452 VBERROR(QString(
"error %1 when writing %2 bytes %3")
455 .
arg((r == SL_RESULT_BUFFER_INSUFFICIENT) ?
" (buffer insufficient)" :
""));
470 if (numBufferesQueued < 0)
482 if (r == SL_RESULT_SUCCESS)
484 if (mb <= SL_MILLIBEL_MIN)
490 volume = lroundf(expf(mb / (3*2000.0F)) * 100);
492 VBAUDIO(QString(
"GetVolume(%1) %2 (%3)")
497 VBERROR(QString(
"GetVolume(%1) %2 (%3) : %4")
507 VBERROR(
"Android volume only supports stereo!");
512 float vol = volume / 100.f;
517 mb = SL_MILLIBEL_MIN;
522 mb = lroundf(3 * 2000.F * log10f(vol));
523 if (mb < SL_MILLIBEL_MIN)
524 mb = SL_MILLIBEL_MIN;
530 if (r == SL_RESULT_SUCCESS)
532 VBAUDIO(QString(
"SetVolume(%1) %2(%3)")
537 VBERROR(QString(
"SetVolume(%1) %2(%3) : %4")
int GetNativeOutputSampleRate(void)
SLObjectItf m_engineObject
SLInterfaceID m_SL_IID_ANDROIDSIMPLEBUFFERQUEUE
void setPassthrough(int val)
AudioOutputSettings * GetOutputSettings(bool digital) override
slCreateEngine_t m_slCreateEnginePtr
void AddSupportedFormat(AudioFormat format)
int GetNumberOfBuffersQueued() const
int GetVolumeChannel(int channel) const override
void Error(const QString &msg)
SLObjectItf m_outputMixObject
void KillAudio(void)
Kill the output thread and cleanup.
int GetBufferedOnSoundcard(void) const override
Return the size in bytes of frames currently in the audio buffer adjusted with the audio playback lat...
arg(title).arg(filename).arg(doDelete))
SLresult(*)(SLObjectItf *, SLuint32, const SLEngineOption *, SLuint32, const SLInterfaceID *, const SLboolean *) slCreateEngine_t
bool OpenDevice(void) override
#define OPENSL_DLSYM(dest, name)
#define CHECK_OPENSL_ERROR(msg)
SLInterfaceID m_SL_IID_PLAY
#define SetPlayState(a, b)
static void SPlayedCallback(SLAndroidSimpleBufferQueueItf caller, void *pContext)
void AddSupportedChannels(int channels)
#define RegisterCallback(a, b, c)
AudioOutputOpenSLES(const AudioSettings &settings)
long m_soundcardBufferSize
#define CreateOutputMix(a, b, c, d, e)
void PlayedCallback(SLAndroidSimpleBufferQueueItf caller)
bool m_init
If set to false, AudioOutput instance will not try to initially open the audio device.
SLInterfaceID m_SL_IID_VOLUME
void Reconfigure(const AudioSettings &settings) override
(Re)Configure AudioOutputBase
void AddSupportedRate(int rate)
#define GetVolumeLevel(a, b)
#define CreateAudioPlayer(a, b, c, d, e, f, g)
AudioFormat m_outputFormat
virtual ~AudioOutputOpenSLES()
#define SetVolumeLevel(a, b)
#define GetInterface(a, b, c)
void CloseDevice(void) override
int m_outputBytesPerFrame
SLInterfaceID m_SL_IID_ENGINE
void InitSettings(const AudioSettings &settings)
SLEngineItf m_engineEngine
#define SetPositionUpdatePeriod(a, b)
SLObjectItf m_playerObject
SLAndroidSimpleBufferQueueItf m_playerBufferQueue
void WriteAudio(unsigned char *aubuf, int size) override
#define POSITIONUPDATEPERIOD
static void usleep(unsigned long time)
void SetVolumeChannel(int channel, int volume) override