play-audio: Build from separate dedicated repo
authorFredrik Fornwall <fredrik@fornwall.net>
Wed, 1 Mar 2017 21:11:53 +0000 (22:11 +0100)
committerFredrik Fornwall <fredrik@fornwall.net>
Wed, 1 Mar 2017 21:11:53 +0000 (22:11 +0100)
packages/play-audio/build.sh
packages/play-audio/play-audio.1 [deleted file]
packages/play-audio/play-audio.cpp [deleted file]

index f87ade8..115ff74 100644 (file)
@@ -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 (file)
index 8c1a073..0000000
+++ /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 (file)
index 38f092e..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-#include <assert.h>
-#include <getopt.h>
-#include <pthread.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <SLES/OpenSLES.h>
-#include <SLES/OpenSLES_Android.h>
-
-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
-       // <SLES/OpenSLES_AndroidConfiguration.h>, 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;
-}