static int aout_open_audio_n(JNIEnv *env, SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained) { assert(desired); SDL_Aout_Opaque *opaque = aout->opaque; opaque->spec = *desired; opaque->atrack = SDL_Android_AudioTrack_new_from_sdl_spec(env, desired); if (!opaque->atrack) { ALOGE("aout_open_audio_n: failed to new AudioTrcak()"); return -1; } opaque->buffer_size = SDL_Android_AudioTrack_get_min_buffer_size(opaque->atrack); if (opaque->buffer_size <= 0) { ALOGE("aout_open_audio_n: failed to getMinBufferSize()"); SDL_Android_AudioTrack_free(env, opaque->atrack); opaque->atrack = NULL; return -1; } opaque->buffer = malloc(opaque->buffer_size); if (!opaque->buffer) { ALOGE("aout_open_audio_n: failed to allocate buffer"); SDL_Android_AudioTrack_free(env, opaque->atrack); opaque->atrack = NULL; return -1; } if (obtained) { SDL_Android_AudioTrack_get_target_spec(opaque->atrack, obtained); SDLTRACE("audio target format fmt:0x%x, channel:0x%x", (int)obtained->format, (int)obtained->channels); } opaque->audio_session_id = SDL_Android_AudioTrack_getAudioSessionId(env, opaque->atrack); ALOGI("audio_session_id = %d\n", opaque->audio_session_id); opaque->pause_on = 1; opaque->abort_request = 0; opaque->audio_tid = SDL_CreateThreadEx(&opaque->_audio_tid, aout_thread, aout, "ff_aout_android"); if (!opaque->audio_tid) { ALOGE("aout_open_audio_n: failed to create audio thread"); SDL_Android_AudioTrack_free(env, opaque->atrack); opaque->atrack = NULL; return -1; } return 0; }
static int aout_thread_n(JNIEnv *env, SDL_Aout *aout) { SDL_Aout_Opaque *opaque = aout->opaque; SDL_Android_AudioTrack *atrack = opaque->atrack; SDL_AudioCallback audio_cblk = opaque->spec.callback; void *userdata = opaque->spec.userdata; uint8_t *buffer = opaque->buffer; int copy_size = opaque->buffer_size; assert(atrack); assert(buffer); SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH); if (!opaque->abort_request && !opaque->pause_on) SDL_Android_AudioTrack_play(env, atrack); while (!opaque->abort_request) { SDL_LockMutex(opaque->wakeup_mutex); if (!opaque->abort_request && opaque->pause_on) { SDL_Android_AudioTrack_pause(env, atrack); while (!opaque->abort_request && opaque->pause_on) { SDL_CondWaitTimeout(opaque->wakeup_cond, opaque->wakeup_mutex, 1000); } if (!opaque->abort_request && !opaque->pause_on) SDL_Android_AudioTrack_play(env, atrack); } if (opaque->need_flush) { opaque->need_flush = 0; SDL_Android_AudioTrack_flush(env, atrack); } if (opaque->need_set_volume) { opaque->need_set_volume = 0; SDL_Android_AudioTrack_set_volume(env, atrack, opaque->left_volume, opaque->right_volume); } SDL_UnlockMutex(opaque->wakeup_mutex); audio_cblk(userdata, buffer, copy_size); if (opaque->need_flush) { SDL_Android_AudioTrack_flush(env, atrack); opaque->need_flush = false; } if (opaque->need_flush) { opaque->need_flush = 0; SDL_Android_AudioTrack_flush(env, atrack); } else { int written = SDL_Android_AudioTrack_write_byte(env, atrack, buffer, copy_size); if (written != copy_size) { ALOGW("AudioTrack: not all data copied %d/%d", (int)written, (int)copy_size); } } // TODO: 1 if callback return -1 or 0 } SDL_Android_AudioTrack_free(env, atrack); return 0; }