Browse Source

Update play-audio to 0.2

Cleanups and stream type support
android-5
Fredrik Fornwall 10 years ago
parent
commit
df22a55439
  1. 2
      packages/play-audio/build.sh
  2. 5
      packages/play-audio/play-audio.1
  3. 97
      packages/play-audio/play-audio.cpp

2
packages/play-audio/build.sh

@ -1,6 +1,6 @@
TERMUX_PKG_HOMEPAGE=http://termux.com TERMUX_PKG_HOMEPAGE=http://termux.com
TERMUX_PKG_DESCRIPTION="Simple commandline audio player for Android" TERMUX_PKG_DESCRIPTION="Simple commandline audio player for Android"
TERMUX_PKG_VERSION=0.1 TERMUX_PKG_VERSION=0.2
termux_step_make_install () { termux_step_make_install () {
$CXX $CFLAGS $LDFLAGS \ $CXX $CFLAGS $LDFLAGS \

5
packages/play-audio/play-audio.1

@ -5,13 +5,16 @@
.Nd audio player using the Android media system .Nd audio player using the Android media system
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm play-audio .Nm play-audio
.Op Fl s Ar stream
.Op Ar files .Op Ar files
.Sh DESCRIPTION .Sh DESCRIPTION
The The
.Nm play-audio .Nm play-audio
utility plays the files listed as arguments, in order, using the Android media system. utility plays one or more files listed as arguments using the Android media system.
.Pp .Pp
The supported media formats may vary across difference devices and Android versions. 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 .Sh EXAMPLES
Play two ogg files in succession: Play two ogg files in succession:
.Pp .Pp

97
packages/play-audio/play-audio.cpp

@ -13,10 +13,21 @@ class AudioPlayer {
AudioPlayer(); AudioPlayer();
~AudioPlayer(); ~AudioPlayer();
void play(char const* uri); 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: private:
SLObjectItf mSlEngineObject{NULL}; SLObjectItf mSlEngineObject{NULL};
SLEngineItf mSlEngineInterface{NULL}; SLEngineItf mSlEngineInterface{NULL};
SLObjectItf mSlOutputMixObject{NULL}; SLObjectItf mSlOutputMixObject{NULL};
SLint32 androidStreamType{SL_ANDROID_STREAM_MEDIA};
}; };
class MutexWithCondition { class MutexWithCondition {
@ -53,10 +64,8 @@ AudioPlayer::AudioPlayer() {
result = (*mSlEngineObject)->GetInterface(mSlEngineObject, SL_IID_ENGINE, &mSlEngineInterface); result = (*mSlEngineObject)->GetInterface(mSlEngineObject, SL_IID_ENGINE, &mSlEngineInterface);
assert(SL_RESULT_SUCCESS == result); assert(SL_RESULT_SUCCESS == result);
SLuint32 const numWantedInterfaces = 1; SLuint32 const numWantedInterfaces = 0;
SLInterfaceID wantedInterfaces[numWantedInterfaces]{ SL_IID_ENVIRONMENTALREVERB }; result = (*mSlEngineInterface)->CreateOutputMix(mSlEngineInterface, &mSlOutputMixObject, numWantedInterfaces, NULL, NULL);
SLboolean wantedInterfacesRequired[numWantedInterfaces]{ SL_BOOLEAN_TRUE };
result = (*mSlEngineInterface)->CreateOutputMix(mSlEngineInterface, &mSlOutputMixObject, numWantedInterfaces, wantedInterfaces, wantedInterfacesRequired);
assert(SL_RESULT_SUCCESS == result); assert(SL_RESULT_SUCCESS == result);
result = (*mSlOutputMixObject)->Realize(mSlOutputMixObject, SL_BOOLEAN_FALSE); result = (*mSlOutputMixObject)->Realize(mSlOutputMixObject, SL_BOOLEAN_FALSE);
@ -73,7 +82,7 @@ void opensl_prefetch_callback(SLPrefetchStatusItf caller, void* pContext, SLuint
(*caller)->GetPrefetchStatus(caller, &status); (*caller)->GetPrefetchStatus(caller, &status);
if (status == SL_PREFETCHSTATUS_UNDERFLOW) { if (status == SL_PREFETCHSTATUS_UNDERFLOW) {
// Level is 0 but we have SL_PREFETCHSTATUS_UNDERFLOW, implying an error. // Level is 0 but we have SL_PREFETCHSTATUS_UNDERFLOW, implying an error.
printf("- ERROR: Underflow when prefetching data and fill level zero\n"); printf("play-audio: underflow when prefetching data\n");
MutexWithCondition* cond = (MutexWithCondition*) pContext; MutexWithCondition* cond = (MutexWithCondition*) pContext;
cond->lockAndSignal(); cond->lockAndSignal();
} }
@ -95,16 +104,10 @@ void AudioPlayer::play(char const* uri)
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, mSlOutputMixObject}; SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, mSlOutputMixObject};
SLDataSink audioSnk = {&loc_outmix, NULL}; SLDataSink audioSnk = {&loc_outmix, NULL};
// SL_IID_ANDROIDCONFIGURATION is Android specific interface, SL_IID_VOLUME is general: // SL_IID_ANDROIDCONFIGURATION is Android specific interface, SL_IID_PREFETCHSTATUS is general:
SLuint32 const numWantedInterfaces = 5; SLuint32 const numWantedInterfaces = 2;
SLInterfaceID wantedInterfaces[numWantedInterfaces]{ SLInterfaceID wantedInterfaces[numWantedInterfaces]{ SL_IID_ANDROIDCONFIGURATION, SL_IID_PREFETCHSTATUS };
SL_IID_ANDROIDCONFIGURATION, SLboolean wantedInterfacesRequired[numWantedInterfaces]{ SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
SL_IID_VOLUME,
SL_IID_PREFETCHSTATUS,
SL_IID_PLAYBACKRATE,
SL_IID_EFFECTSEND
};
SLboolean wantedInterfacesRequired[numWantedInterfaces]{ SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
SLObjectItf uriPlayerObject = NULL; SLObjectItf uriPlayerObject = NULL;
SLresult result = (*mSlEngineInterface)->CreateAudioPlayer(mSlEngineInterface, &uriPlayerObject, &audioSrc, &audioSnk, SLresult result = (*mSlEngineInterface)->CreateAudioPlayer(mSlEngineInterface, &uriPlayerObject, &audioSrc, &audioSnk,
@ -119,21 +122,7 @@ void AudioPlayer::play(char const* uri)
result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_ANDROIDCONFIGURATION, &androidConfig); result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_ANDROIDCONFIGURATION, &androidConfig);
assert(SL_RESULT_SUCCESS == result); assert(SL_RESULT_SUCCESS == result);
// This allows setting the stream type (default:SL_ANDROID_STREAM_MEDIA): result = (*androidConfig)->SetConfiguration(androidConfig, SL_ANDROID_KEY_STREAM_TYPE, &this->androidStreamType, sizeof(SLint32));
/* same as android.media.AudioManager.STREAM_VOICE_CALL */
// #define SL_ANDROID_STREAM_VOICE ((SLint32) 0x00000000)
/* same as android.media.AudioManager.STREAM_SYSTEM */
// #define SL_ANDROID_STREAM_SYSTEM ((SLint32) 0x00000001)
/* same as android.media.AudioManager.STREAM_RING */
// #define SL_ANDROID_STREAM_RING ((SLint32) 0x00000002)
/* same as android.media.AudioManager.STREAM_MUSIC */
// #define SL_ANDROID_STREAM_MEDIA ((SLint32) 0x00000003)
/* same as android.media.AudioManager.STREAM_ALARM */
// #define SL_ANDROID_STREAM_ALARM ((SLint32) 0x00000004)
/* same as android.media.AudioManager.STREAM_NOTIFICATION */
// #define SL_ANDROID_STREAM_NOTIFICATION ((SLint32) 0x00000005)
SLint32 androidStreamType = SL_ANDROID_STREAM_ALARM;
result = (*androidConfig)->SetConfiguration(androidConfig, SL_ANDROID_KEY_STREAM_TYPE, &androidStreamType, sizeof(SLint32));
assert(SL_RESULT_SUCCESS == result); assert(SL_RESULT_SUCCESS == result);
// We now Realize(). Note that the android config needs to be done before, but getting the SLPrefetchStatusItf after. // We now Realize(). Note that the android config needs to be done before, but getting the SLPrefetchStatusItf after.
@ -148,10 +137,6 @@ void AudioPlayer::play(char const* uri)
result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_PLAY, &uriPlayerPlay); result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_PLAY, &uriPlayerPlay);
assert(SL_RESULT_SUCCESS == result); assert(SL_RESULT_SUCCESS == result);
SLPlaybackRateItf playbackRateInterface;
result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_PLAYBACKRATE, &playbackRateInterface);
assert(SL_RESULT_SUCCESS == result);
if (NULL == uriPlayerPlay) { if (NULL == uriPlayerPlay) {
fprintf(stderr, "Cannot play '%s'\n", uri); fprintf(stderr, "Cannot play '%s'\n", uri);
} else { } else {
@ -194,19 +179,53 @@ int main(int argc, char** argv)
{ {
bool help = false; bool help = false;
int c; int c;
while ((c = getopt(argc, argv, "h")) != -1) { char* streamType = NULL;
while ((c = getopt(argc, argv, "hs:")) != -1) {
switch (c) { switch (c) {
case 'h': help = true; break; case 'h':
case '?': help = true; break;
case 's': streamType = optarg; break;
} }
} }
if (help || optind == argc) { if (help || optind == argc) {
printf("usage: %s [files]\n", argv[0]); printf("usage: play-audio [-s streamtype] [files]\n");
exit(0); return 1;
} }
AudioPlayer player; AudioPlayer player;
for (int i = optind; i < argc; i++) player.play(argv[i]);
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; return 0;
} }

Loading…
Cancel
Save