1 /***
2     This file is part of snapcast
3     Copyright (C) 2014-2021  Johannes Pohl
4 
5     This program is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 ***/
18 
19 #include <assert.h>
20 #include <iostream>
21 
22 #include "common/aixlog.hpp"
23 #include "common/snap_exception.hpp"
24 #include "common/str_compat.hpp"
25 #include "opensl_player.hpp"
26 
27 using namespace std;
28 
29 namespace player
30 {
31 
32 static constexpr auto LOG_TAG = "OpenSlPlayer";
33 
34 static constexpr auto kPhaseInit = "Init";
35 static constexpr auto kPhaseStart = "Start";
36 static constexpr auto kPhaseStop = "Stop";
37 
38 
39 // http://stackoverflow.com/questions/35730050/android-with-nexus-6-how-to-avoid-decreased-opensl-audio-thread-priority-rela?rq=1
40 
41 // source: https://github.com/hrydgard/native/blob/master/android/native-audio-so.cpp
42 // https://android.googlesource.com/platform/development/+/c21a505/ndk/platforms/android-9/samples/native-audio/jni/native-audio-jni.c
43 
44 // This callback handler is called every time a buffer finishes playing.
45 // The documentation available is very unclear about how to best manage buffers.
46 // I've chosen to this approach: Instantly enqueue a buffer that was rendered to the last time,
47 // and then render the next. Hopefully it's okay to spend time in this callback after having enqueued.
bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq,void * context)48 static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void* context)
49 {
50     OpenslPlayer* player = static_cast<OpenslPlayer*>(context);
51     player->playerCallback(bq);
52 }
53 
54 
OpenslPlayer(boost::asio::io_context & io_context,const ClientSettings::Player & settings,std::shared_ptr<Stream> stream)55 OpenslPlayer::OpenslPlayer(boost::asio::io_context& io_context, const ClientSettings::Player& settings, std::shared_ptr<Stream> stream)
56     : Player(io_context, settings, stream), engineObject(nullptr), engineEngine(nullptr), outputMixObject(nullptr), bqPlayerObject(nullptr),
57       bqPlayerPlay(nullptr), bqPlayerBufferQueue(nullptr), bqPlayerVolume(nullptr), curBuffer(0), ms_(50), buff_size(0), pubStream_(stream)
58 {
59     initOpensl();
60 }
61 
62 
~OpenslPlayer()63 OpenslPlayer::~OpenslPlayer()
64 {
65     uninitOpensl();
66 }
67 
68 
playerCallback(SLAndroidSimpleBufferQueueItf bq)69 void OpenslPlayer::playerCallback(SLAndroidSimpleBufferQueueItf bq)
70 {
71     if (bq != bqPlayerBufferQueue)
72     {
73         LOG(ERROR, LOG_TAG) << "Wrong bq!\n";
74         return;
75     }
76 
77     if (!active_)
78         return;
79 
80     chronos::usec delay(ms_ * 1000);
81     if (!pubStream_->getPlayerChunkOrSilence(buffer[curBuffer], delay, frames_))
82     {
83         // LOG(INFO, LOG_TAG) << "Failed to get chunk. Playing silence.\n";
84     }
85     else
86     {
87         adjustVolume(buffer[curBuffer], frames_);
88     }
89 
90     while (active_)
91     {
92         SLresult result = (*bq)->Enqueue(bq, buffer[curBuffer], buff_size);
93         if (result == SL_RESULT_BUFFER_INSUFFICIENT)
94             chronos::sleep(1);
95         else
96             break;
97     }
98 
99     curBuffer ^= 1; // Switch buffer
100 }
101 
102 
resultToString(SLresult result) const103 std::string OpenslPlayer::resultToString(SLresult result) const
104 {
105     switch (result)
106     {
107         case SL_RESULT_SUCCESS:
108             return "SL_RESULT_SUCCESS";
109         case SL_RESULT_PRECONDITIONS_VIOLATED:
110             return "SL_RESULT_PRECONDITIONS_VIOLATED";
111         case SL_RESULT_PARAMETER_INVALID:
112             return "SL_RESULT_PARAMETER_INVALID";
113         case SL_RESULT_MEMORY_FAILURE:
114             return "SL_RESULT_MEMORY_FAILURE";
115         case SL_RESULT_RESOURCE_ERROR:
116             return "SL_RESULT_RESOURCE_ERROR";
117         case SL_RESULT_RESOURCE_LOST:
118             return "SL_RESULT_RESOURCE_LOST";
119         case SL_RESULT_IO_ERROR:
120             return "SL_RESULT_IO_ERROR";
121         case SL_RESULT_BUFFER_INSUFFICIENT:
122             return "SL_RESULT_BUFFER_INSUFFICIENT";
123         case SL_RESULT_CONTENT_CORRUPTED:
124             return "SL_RESULT_CONTENT_CORRUPTED";
125         case SL_RESULT_CONTENT_UNSUPPORTED:
126             return "SL_RESULT_CONTENT_UNSUPPORTED";
127         case SL_RESULT_CONTENT_NOT_FOUND:
128             return "SL_RESULT_CONTENT_NOT_FOUND";
129         case SL_RESULT_PERMISSION_DENIED:
130             return "SL_RESULT_PERMISSION_DENIED";
131         case SL_RESULT_FEATURE_UNSUPPORTED:
132             return "SL_RESULT_FEATURE_UNSUPPORTED";
133         case SL_RESULT_INTERNAL_ERROR:
134             return "SL_RESULT_INTERNAL_ERROR";
135         case SL_RESULT_UNKNOWN_ERROR:
136             return "SL_RESULT_UNKNOWN_ERROR";
137         case SL_RESULT_OPERATION_ABORTED:
138             return "SL_RESULT_OPERATION_ABORTED";
139         case SL_RESULT_CONTROL_LOST:
140             return "SL_RESULT_CONTROL_LOST";
141         default:
142             return "UNKNOWN";
143     }
144 }
145 
146 
needsThread() const147 bool OpenslPlayer::needsThread() const
148 {
149     return false;
150 }
151 
152 
throwUnsuccess(const std::string & phase,const std::string & what,SLresult result)153 void OpenslPlayer::throwUnsuccess(const std::string& phase, const std::string& what, SLresult result)
154 {
155     if (SL_RESULT_SUCCESS == result)
156         return;
157     stringstream ss;
158     ss << phase << " failed, operation: " << what << ", result: " << resultToString(result) << "(" << result << ")";
159     throw SnapException(ss.str());
160 }
161 
162 
initOpensl()163 void OpenslPlayer::initOpensl()
164 {
165     if (active_)
166         return;
167 
168     LOG(INFO, LOG_TAG) << "Init start\n";
169 
170     const SampleFormat& format = stream_->getFormat();
171 
172 
173     frames_ = format.rate() / (1000 / ms_); // * format.channels(); // 1920; // 48000 * 2 / 50  // => 50ms
174 
175     buff_size = frames_ * format.frameSize() /* 2 -> sample size */;
176     LOG(INFO, LOG_TAG) << "frames: " << frames_ << ", channels: " << format.channels() << ", rate: " << format.rate() << ", buff: " << buff_size << "\n";
177 
178     SLresult result;
179     // create engine
180     SLEngineOption engineOption[] = {{(SLuint32)SL_ENGINEOPTION_THREADSAFE, (SLuint32)SL_BOOLEAN_TRUE}};
181     result = slCreateEngine(&engineObject, 1, engineOption, 0, nullptr, nullptr);
182     throwUnsuccess(kPhaseInit, "slCreateEngine", result);
183     result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
184     throwUnsuccess(kPhaseInit, "EngineObject::Realize", result);
185     result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
186     throwUnsuccess(kPhaseInit, "EngineObject::GetInterface", result);
187     result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, 0, 0);
188     throwUnsuccess(kPhaseInit, "EngineEngine::CreateOutputMix", result);
189     result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
190     throwUnsuccess(kPhaseInit, "OutputMixObject::Realize", result);
191 
192     SLuint32 samplesPerSec = SL_SAMPLINGRATE_48;
193     switch (format.rate())
194     {
195         case 8000:
196             samplesPerSec = SL_SAMPLINGRATE_8;
197             break;
198         case 11025:
199             samplesPerSec = SL_SAMPLINGRATE_11_025;
200             break;
201         case 16000:
202             samplesPerSec = SL_SAMPLINGRATE_16;
203             break;
204         case 22050:
205             samplesPerSec = SL_SAMPLINGRATE_22_05;
206             break;
207         case 24000:
208             samplesPerSec = SL_SAMPLINGRATE_24;
209             break;
210         case 32000:
211             samplesPerSec = SL_SAMPLINGRATE_32;
212             break;
213         case 44100:
214             samplesPerSec = SL_SAMPLINGRATE_44_1;
215             break;
216         case 48000:
217             samplesPerSec = SL_SAMPLINGRATE_48;
218             break;
219         case 64000:
220             samplesPerSec = SL_SAMPLINGRATE_64;
221             break;
222         case 88200:
223             samplesPerSec = SL_SAMPLINGRATE_88_2;
224             break;
225         case 96000:
226             samplesPerSec = SL_SAMPLINGRATE_96;
227             break;
228         case 192000:
229             samplesPerSec = SL_SAMPLINGRATE_192;
230             break;
231         default:
232             throw SnapException("Sample rate not supported");
233     }
234 
235     SLuint32 bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
236     SLuint32 containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
237     switch (format.bits())
238     {
239         case 8:
240             bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_8;
241             containerSize = SL_PCMSAMPLEFORMAT_FIXED_8;
242             break;
243         case 16:
244             bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
245             containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
246             break;
247         case 24:
248             bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_24;
249             containerSize = SL_PCMSAMPLEFORMAT_FIXED_32;
250             break;
251         case 32:
252             bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_32;
253             containerSize = SL_PCMSAMPLEFORMAT_FIXED_32;
254             break;
255         default:
256             throw SnapException("Unsupported sample format: " + cpt::to_string(format.bits()));
257     }
258 
259 
260     SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
261     SLDataFormat_PCM format_pcm = {
262         SL_DATAFORMAT_PCM,        format.channels(), samplesPerSec, bitsPerSample, containerSize, SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
263         SL_BYTEORDER_LITTLEENDIAN};
264 
265     SLDataSource audioSrc = {&loc_bufq, &format_pcm};
266 
267     // configure audio sink
268     SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
269     SLDataSink audioSnk = {&loc_outmix, nullptr};
270 
271     // create audio player
272     const SLInterfaceID ids[3] = {SL_IID_ANDROIDCONFIGURATION, SL_IID_PLAY, SL_IID_BUFFERQUEUE}; //, SL_IID_VOLUME};
273     const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};                //, SL_BOOLEAN_TRUE};
274     result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 3, ids, req);
275     throwUnsuccess(kPhaseInit, "Engine::CreateAudioPlayer", result);
276 
277     SLAndroidConfigurationItf playerConfig;
278     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_ANDROIDCONFIGURATION, &playerConfig);
279     throwUnsuccess(kPhaseInit, "PlayerObject::GetInterface", result);
280     SLint32 streamType = SL_ANDROID_STREAM_MEDIA;
281     ////	SLint32 streamType = SL_ANDROID_STREAM_VOICE;
282     result = (*playerConfig)->SetConfiguration(playerConfig, SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32));
283     throwUnsuccess(kPhaseInit, "PlayerConfig::SetConfiguration", result);
284     // Set the performance mode.
285     SLuint32 performanceMode = SL_ANDROID_PERFORMANCE_NONE;
286     result = (*playerConfig)->SetConfiguration(playerConfig, SL_ANDROID_KEY_PERFORMANCE_MODE, &performanceMode, sizeof(performanceMode));
287 
288     result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
289     throwUnsuccess(kPhaseInit, "PlayerObject::Realize", result);
290     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
291     throwUnsuccess(kPhaseInit, "PlayerObject::GetInterface", result);
292     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, &bqPlayerBufferQueue);
293     throwUnsuccess(kPhaseInit, "PlayerObject::GetInterface", result);
294     result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, this);
295     throwUnsuccess(kPhaseInit, "PlayerBufferQueue::RegisterCallback", result);
296     //	result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
297     //	throwUnsuccess("PlayerObject::GetInterface", result);
298     result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PAUSED);
299     throwUnsuccess(kPhaseInit, "PlayerPlay::SetPlayState", result);
300 
301     // Render and enqueue a first buffer. (or should we just play the buffer empty?)
302     curBuffer = 0;
303     buffer[0] = new char[buff_size];
304     buffer[1] = new char[buff_size];
305 
306     active_ = true;
307 
308     memset(buffer[curBuffer], 0, buff_size);
309     result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[curBuffer], sizeof(buffer[curBuffer]));
310     throwUnsuccess(kPhaseInit, "PlayerBufferQueue::Enqueue", result);
311     curBuffer ^= 1;
312     LOG(INFO, LOG_TAG) << "Init done\n";
313 }
314 
315 
uninitOpensl()316 void OpenslPlayer::uninitOpensl()
317 {
318     //	if (!active_)
319     //		return;
320 
321     LOG(INFO, LOG_TAG) << "uninitOpensl\n";
322     SLresult result;
323     LOG(INFO, LOG_TAG) << "OpenSLWrap_Shutdown - stopping playback\n";
324     if (bqPlayerPlay != nullptr)
325     {
326         result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED);
327         if (SL_RESULT_SUCCESS != result)
328             LOG(ERROR, LOG_TAG) << "SetPlayState failed\n";
329     }
330 
331     LOG(INFO, LOG_TAG) << "OpenSLWrap_Shutdown - deleting player object\n";
332 
333     if (bqPlayerObject != nullptr)
334     {
335         (*bqPlayerObject)->Destroy(bqPlayerObject);
336         bqPlayerObject = nullptr;
337         bqPlayerPlay = nullptr;
338         bqPlayerBufferQueue = nullptr;
339         bqPlayerVolume = nullptr;
340     }
341 
342     LOG(INFO, LOG_TAG) << "OpenSLWrap_Shutdown - deleting mix object\n";
343 
344     if (outputMixObject != nullptr)
345     {
346         (*outputMixObject)->Destroy(outputMixObject);
347         outputMixObject = nullptr;
348     }
349 
350     LOG(INFO, LOG_TAG) << "OpenSLWrap_Shutdown - deleting engine object\n";
351 
352     if (engineObject != nullptr)
353     {
354         (*engineObject)->Destroy(engineObject);
355         engineObject = nullptr;
356         engineEngine = nullptr;
357     }
358 
359     delete[] buffer[0];
360     buffer[0] = nullptr;
361 
362     delete[] buffer[1];
363     buffer[1] = nullptr;
364 
365     LOG(INFO, LOG_TAG) << "OpenSLWrap_Shutdown - finished\n";
366     active_ = false;
367 }
368 
369 
start()370 void OpenslPlayer::start()
371 {
372     SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
373     throwUnsuccess(kPhaseStart, "PlayerPlay::SetPlayState", result);
374 }
375 
376 
stop()377 void OpenslPlayer::stop()
378 {
379     SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED);
380     (*bqPlayerBufferQueue)->Clear(bqPlayerBufferQueue);
381     throwUnsuccess(kPhaseStop, "PlayerPlay::SetPlayState", result);
382 }
383 
384 } // namespace player
385