From 0af3030f6ed1465e30a168a578849106a21447a5 Mon Sep 17 00:00:00 2001 From: Fredrik Fornwall Date: Wed, 1 Mar 2017 22:11:53 +0100 Subject: [PATCH] play-audio: Build from separate dedicated repo --- packages/play-audio/build.sh | 25 ++- packages/play-audio/play-audio.1 | 25 --- packages/play-audio/play-audio.cpp | 235 ----------------------------- 3 files changed, 10 insertions(+), 275 deletions(-) delete mode 100644 packages/play-audio/play-audio.1 delete mode 100644 packages/play-audio/play-audio.cpp diff --git a/packages/play-audio/build.sh b/packages/play-audio/build.sh index f87ade8bf..115ff7479 100644 --- a/packages/play-audio/build.sh +++ b/packages/play-audio/build.sh @@ -1,27 +1,22 @@ -TERMUX_PKG_HOMEPAGE=http://termux.com +TERMUX_PKG_HOMEPAGE=https://github.com/termux/play-audio TERMUX_PKG_DESCRIPTION="Simple commandline audio player for Android" TERMUX_PKG_VERSION=0.4 +TERMUX_PKG_SRCURL=https://github.com/termux/play-audio/archive/v${TERMUX_PKG_VERSION}.tar.gz +TERMUX_PKG_SHA256=95d495d2692b4ac13b5d0c9f680410f0c08e563ea67ae8de0089c7d9366fa223 +TERMUX_PKG_FOLDERNAME=play-audio-$TERMUX_PKG_VERSION +TERMUX_PKG_BUILD_IN_SRC=yes -termux_step_make_install () { +termux_step_post_make_install () { local LIBEXEC_BINARY=$TERMUX_PREFIX/libexec/play-audio - # Use $CC instead of $CXX to link in order to avoid linking - # against libgnustl_shared.so, since the launcher script - # below removes LD_LIBRARY_PATH. - $CC $CFLAGS $LDFLAGS \ - -std=c++14 -Wall -Wextra -pedantic -Werror \ - -fno-exceptions \ - -lOpenSLES \ - $TERMUX_PKG_BUILDER_DIR/play-audio.cpp -o $LIBEXEC_BINARY + local BIN_BINARY=$TERMUX_PREFIX/bin/play-audio + mv $BIN_BINARY $LIBEXEC_BINARY - cat << EOF > $TERMUX_PREFIX/bin/play-audio + cat << EOF > $BIN_BINARY #!/bin/sh # Avoid linker errors due to libOpenSLES.so: LD_LIBRARY_PATH= exec $LIBEXEC_BINARY "\$@" EOF - chmod +x $TERMUX_PREFIX/bin/play-audio - - mkdir -p $TERMUX_PREFIX/share/man/man1/ - cp $TERMUX_PKG_BUILDER_DIR/play-audio.1 $TERMUX_PREFIX/share/man/man1/ + chmod +x $BIN_BINARY } diff --git a/packages/play-audio/play-audio.1 b/packages/play-audio/play-audio.1 deleted file mode 100644 index 8c1a073b0..000000000 --- a/packages/play-audio/play-audio.1 +++ /dev/null @@ -1,25 +0,0 @@ -.Dd July 27 2015 -.Dt play-audio 1 -.Sh NAME -.Nm play-audio -.Nd audio player using the Android media system -.Sh SYNOPSIS -.Nm play-audio -.Op Fl s Ar stream -.Op Ar files -.Sh DESCRIPTION -The -.Nm play-audio -utility plays one or more files listed as arguments using the Android media system. -.Pp -The supported media formats may vary across difference devices and Android versions. -.Pp -The audio stream type (which affects the volume) may be specified as 'alarm', 'media' (default), 'notification', 'ring', 'system' or 'voice'. -.Sh EXAMPLES -Play two ogg files in succession: -.Pp -.Dl $ play-audio path/to/first.ogg path/to/second.ogg -.Pp -.Sh AUTHOR -.An Fredrik Fornwall Aq Mt fredrik@fornwall.net - diff --git a/packages/play-audio/play-audio.cpp b/packages/play-audio/play-audio.cpp deleted file mode 100644 index 38f092e92..000000000 --- a/packages/play-audio/play-audio.cpp +++ /dev/null @@ -1,235 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class AudioPlayer { - public: - AudioPlayer(); - ~AudioPlayer(); - void play(char const* uri); - /** - * This allows setting the stream type (default:SL_ANDROID_STREAM_MEDIA): - * SL_ANDROID_STREAM_ALARM - same as android.media.AudioManager.STREAM_ALARM - * SL_ANDROID_STREAM_MEDIA - same as android.media.AudioManager.STREAM_MUSIC - * SL_ANDROID_STREAM_NOTIFICATION - same as android.media.AudioManager.STREAM_NOTIFICATION - * SL_ANDROID_STREAM_RING - same as android.media.AudioManager.STREAM_RING - * SL_ANDROID_STREAM_SYSTEM - same as android.media.AudioManager.STREAM_SYSTEM - * SL_ANDROID_STREAM_VOICE - same as android.media.AudioManager.STREAM_VOICE_CALL - */ - void setStreamType(SLint32 streamType) { this->androidStreamType = streamType; } - private: - SLObjectItf mSlEngineObject{NULL}; - SLEngineItf mSlEngineInterface{NULL}; - SLObjectItf mSlOutputMixObject{NULL}; - SLint32 androidStreamType{SL_ANDROID_STREAM_MEDIA}; -}; - -class MutexWithCondition { - public: - MutexWithCondition() { - pthread_mutex_init(&mutex, NULL); - pthread_cond_init(&condition, NULL); - pthread_mutex_lock(&mutex); - } - ~MutexWithCondition() { pthread_mutex_unlock(&mutex); } - void waitFor() { while (!occurred) pthread_cond_wait(&condition, &mutex); } - /** From waking thread. */ - void lockAndSignal() { - pthread_mutex_lock(&mutex); - occurred = true; - pthread_cond_signal(&condition); - pthread_mutex_unlock(&mutex); - } - private: - volatile bool occurred{false}; - pthread_mutex_t mutex; - pthread_cond_t condition; -}; - -AudioPlayer::AudioPlayer() { - // "OpenSL ES for Android is designed for multi-threaded applications, and is thread-safe. - // OpenSL ES for Android supports a single engine per application, and up to 32 objects. - // Available device memory and CPU may further restrict the usable number of objects. - // slCreateEngine recognizes, but ignores, these engine options: SL_ENGINEOPTION_THREADSAFE SL_ENGINEOPTION_LOSSOFCONTROL" - SLresult result = slCreateEngine(&mSlEngineObject, - /*numOptions=*/0, /*options=*/NULL, - /*numWantedInterfaces=*/0, /*wantedInterfaces=*/NULL, /*wantedInterfacesRequired=*/NULL); - assert(SL_RESULT_SUCCESS == result); - - result = (*mSlEngineObject)->Realize(mSlEngineObject, SL_BOOLEAN_FALSE); - assert(SL_RESULT_SUCCESS == result); - - result = (*mSlEngineObject)->GetInterface(mSlEngineObject, SL_IID_ENGINE, &mSlEngineInterface); - assert(SL_RESULT_SUCCESS == result); - - SLuint32 const numWantedInterfaces = 0; - result = (*mSlEngineInterface)->CreateOutputMix(mSlEngineInterface, &mSlOutputMixObject, numWantedInterfaces, NULL, NULL); - assert(SL_RESULT_SUCCESS == result); - - result = (*mSlOutputMixObject)->Realize(mSlOutputMixObject, SL_BOOLEAN_FALSE); - assert(SL_RESULT_SUCCESS == result); - -} - -void opensl_prefetch_callback(SLPrefetchStatusItf caller, void* pContext, SLuint32 event) { - if (event & SL_PREFETCHEVENT_STATUSCHANGE) { - SLpermille level = 0; - (*caller)->GetFillLevel(caller, &level); - if (level == 0) { - SLuint32 status; - (*caller)->GetPrefetchStatus(caller, &status); - if (status == SL_PREFETCHSTATUS_UNDERFLOW) { - // Level is 0 but we have SL_PREFETCHSTATUS_UNDERFLOW, implying an error. - printf("play-audio: underflow when prefetching data\n"); - MutexWithCondition* cond = (MutexWithCondition*) pContext; - cond->lockAndSignal(); - } - } - } -} - -void opensl_player_callback(SLPlayItf /*caller*/, void* pContext, SLuint32 /*event*/) { - MutexWithCondition* condition = (MutexWithCondition*) pContext; - condition->lockAndSignal(); -} - -void AudioPlayer::play(char const* uri) -{ - SLDataLocator_URI loc_uri = {SL_DATALOCATOR_URI, (SLchar *) uri}; - SLDataFormat_MIME format_mime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED}; - SLDataSource audioSrc = {&loc_uri, &format_mime}; - - SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, mSlOutputMixObject}; - SLDataSink audioSnk = {&loc_outmix, NULL}; - - // SL_IID_ANDROIDCONFIGURATION is Android specific interface, SL_IID_PREFETCHSTATUS is general: - SLuint32 const numWantedInterfaces = 2; - SLInterfaceID wantedInterfaces[numWantedInterfaces]{ SL_IID_ANDROIDCONFIGURATION, SL_IID_PREFETCHSTATUS }; - SLboolean wantedInterfacesRequired[numWantedInterfaces]{ SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE }; - - SLObjectItf uriPlayerObject = NULL; - SLresult result = (*mSlEngineInterface)->CreateAudioPlayer(mSlEngineInterface, &uriPlayerObject, &audioSrc, &audioSnk, - numWantedInterfaces, wantedInterfaces, wantedInterfacesRequired); - assert(SL_RESULT_SUCCESS == result); - - // Android specific interface - usage: - // SLresult (*GetInterface) (SLObjectItf self, const SLInterfaceID iid, void* pInterface); - // This function gives different interfaces. One is android-specific, from - // , done before realization: - SLAndroidConfigurationItf androidConfig; - result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_ANDROIDCONFIGURATION, &androidConfig); - assert(SL_RESULT_SUCCESS == result); - - result = (*androidConfig)->SetConfiguration(androidConfig, SL_ANDROID_KEY_STREAM_TYPE, &this->androidStreamType, sizeof(SLint32)); - assert(SL_RESULT_SUCCESS == result); - - // We now Realize(). Note that the android config needs to be done before, but getting the SLPrefetchStatusItf after. - result = (*uriPlayerObject)->Realize(uriPlayerObject, /*async=*/SL_BOOLEAN_FALSE); - assert(SL_RESULT_SUCCESS == result); - - SLPrefetchStatusItf prefetchInterface; - result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_PREFETCHSTATUS, &prefetchInterface); - assert(SL_RESULT_SUCCESS == result); - - SLPlayItf uriPlayerPlay = NULL; - result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_PLAY, &uriPlayerPlay); - assert(SL_RESULT_SUCCESS == result); - - if (NULL == uriPlayerPlay) { - fprintf(stderr, "Cannot play '%s'\n", uri); - } else { - result = (*uriPlayerPlay)->SetCallbackEventsMask(uriPlayerPlay, SL_PLAYEVENT_HEADSTALLED | SL_PLAYEVENT_HEADATEND); - assert(SL_RESULT_SUCCESS == result); - - MutexWithCondition condition; - result = (*uriPlayerPlay)->RegisterCallback(uriPlayerPlay, opensl_player_callback, &condition); - assert(SL_RESULT_SUCCESS == result); - - result = (*prefetchInterface)->RegisterCallback(prefetchInterface, opensl_prefetch_callback, &condition); - assert(SL_RESULT_SUCCESS == result); - result = (*prefetchInterface)->SetCallbackEventsMask(prefetchInterface, SL_PREFETCHEVENT_FILLLEVELCHANGE | SL_PREFETCHEVENT_STATUSCHANGE); - - // "For an audio player with URI data source, Object::Realize allocates resources but does not - // connect to the data source (i.e. "prepare") or begin pre-fetching data. These occur once the - // player state is set to either SL_PLAYSTATE_PAUSED or SL_PLAYSTATE_PLAYING." - // - http://mobilepearls.com/labs/native-android-api/ndk/docs/opensles/index.html - result = (*uriPlayerPlay)->SetPlayState(uriPlayerPlay, SL_PLAYSTATE_PLAYING); - assert(SL_RESULT_SUCCESS == result); - - condition.waitFor(); - } - - if (uriPlayerObject != NULL) (*uriPlayerObject)->Destroy(uriPlayerObject); -} - - -AudioPlayer::~AudioPlayer() -{ - // "Be sure to destroy all objects on exit from your application. Objects should be destroyed in reverse order of their creation, - // as it is not safe to destroy an object that has any dependent objects. For example, destroy in this order: audio players - // and recorders, output mix, then finally the engine." - if (mSlOutputMixObject != NULL) { (*mSlOutputMixObject)->Destroy(mSlOutputMixObject); mSlOutputMixObject = NULL; } - if (mSlEngineObject != NULL) { (*mSlEngineObject)->Destroy(mSlEngineObject); mSlEngineObject = NULL; } -} - - -int main(int argc, char** argv) -{ - bool help = false; - int c; - char* streamType = NULL; - while ((c = getopt(argc, argv, "hs:")) != -1) { - switch (c) { - case 'h': - case '?': help = true; break; - case 's': streamType = optarg; break; - } - } - - if (help || optind == argc) { - printf("usage: play-audio [-s streamtype] [files]\n"); - return 1; - } - - AudioPlayer player; - - if (streamType != NULL) { - SLint32 streamTypeEnum; - if (strcmp("alarm", streamType) == 0) { - streamTypeEnum = SL_ANDROID_STREAM_ALARM; - } else if (strcmp("media", streamType) == 0) { - streamTypeEnum = SL_ANDROID_STREAM_MEDIA; - } else if (strcmp("notification", streamType) == 0) { - streamTypeEnum = SL_ANDROID_STREAM_NOTIFICATION; - } else if (strcmp("ring", streamType) == 0) { - streamTypeEnum = SL_ANDROID_STREAM_RING; - } else if (strcmp("system", streamType) == 0) { - streamTypeEnum = SL_ANDROID_STREAM_SYSTEM; - } else if (strcmp("voice", streamType) == 0) { - streamTypeEnum = SL_ANDROID_STREAM_VOICE; - } else { - fprintf(stderr, "play-audio: invalid streamtype '%s'\n", streamType); - return 1; - } - player.setStreamType(streamTypeEnum); - } - - for (int i = optind; i < argc; i++) { - if (access(argv[i], R_OK) != 0) { - fprintf(stderr, "play-audio: '%s' is not a readable file\n", argv[i]); - return 1; - } - } - - for (int i = optind; i < argc; i++) { - player.play(argv[i]); - } - - return 0; -}