Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /***************************************************************************
- * __________ __ ___.
- * Open \______ \ ____ ____ | | _\_ |__ _______ ___
- * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
- * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
- * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
- * \/ \/ \/ \/ \/
- * $Id: pcm-android.c 29826 2011-05-05 19:20:58Z bluebrother $
- *
- * Copyright (c) 2010 Thomas Martitz
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
- #include <jni.h>
- #include <stdbool.h>
- #define _SYSTEM_WITH_JNI /* for getJavaEnvironment */
- #include <system.h>
- #include <pthread.h>
- #include "debug.h"
- #include "pcm.h"
- extern JNIEnv *env_ptr;
- /* infos about our pcm chunks */
- static size_t pcm_data_size;
- static char *pcm_data_start;
- static int audio_locked = 0;
- static struct pthread_mutex audio_lock_mutex = PTHREAD_MUTEX_INITIALIZER;
- /* cache frequently called methods */
- static jmethodID play_pause_method;
- static jmethodID stop_method;
- static jmethodID set_volume_method;
- static jclass RockboxPCM_class;
- static jobject RockboxPCM_instance;
- /*
- * mutex lock/unlock wrappers neatness' sake
- */
- static inline void lock_audio(void)
- {
- pthread_mutex_lock(&audio_lock_mutex);
- }
- static inline void unlock_audio(void)
- {
- pthread_mutex_unlock(&audio_lock_mutex);
- }
- /*
- * transfer our raw data into a java array
- *
- * a bit of a monster functions, but it should cover all cases to overcome
- * the issue that the chunk size of the java layer and our pcm chunks are
- * differently sized
- *
- * afterall, it only copies the raw pcm data from pcm_data_start to
- * the passed byte[]-array
- *
- * it is called from the PositionMarker callback of AudioTrack
- **/
- JNIEXPORT void JNICALL
- Java_org_rockbox_RockboxPCM_pcmSamplesToByteArray(JNIEnv *env,
- jobject this,
- jbyteArray arr)
- {
- lock_audio();
- (void)this;
- size_t len;
- size_t array_size = (*env)->GetArrayLength(env, arr);
- if (array_size > pcm_data_size)
- len = pcm_data_size;
- else
- len = array_size;
- (*env)->SetByteArrayRegion(env, arr, 0, len, pcm_data_start);
- if (array_size > pcm_data_size)
- { /* didn't have enough data for the array ? */
- size_t remaining = array_size - pcm_data_size;
- size_t offset = len;
- retry:
- pcm_play_get_more_callback((void**)&pcm_data_start, &pcm_data_size);
- if (pcm_data_size == 0)
- {
- DEBUGF("out of data\n");
- unlock_audio();
- return;
- }
- if (remaining > pcm_data_size)
- { /* got too little data, get more ... */
- (*env)->SetByteArrayRegion(env, arr, offset, pcm_data_size, pcm_data_start);
- /* advance in the java array by the amount we copied */
- offset += pcm_data_size;
- /* we copied at least a bit */
- remaining -= pcm_data_size;
- pcm_data_size = 0;
- pcm_play_dma_started_callback();
- /* let's get another buch of data and try again */
- goto retry;
- }
- else
- {
- (*env)->SetByteArrayRegion(env, arr, offset, remaining, pcm_data_start);
- pcm_play_dma_started_callback();
- }
- len = remaining;
- }
- pcm_data_start += len;
- pcm_data_size -= len;
- unlock_audio();
- }
- void pcm_play_lock(void)
- {
- if (++audio_locked == 1)
- lock_audio();
- }
- void pcm_play_unlock(void)
- {
- if (--audio_locked == 0);
- unlock_audio();
- }
- void pcm_dma_apply_settings(void)
- {
- }
- void pcm_play_dma_start(const void *addr, size_t size)
- {
- pcm_data_start = (char*)addr;
- pcm_data_size = size;
- pcm_play_dma_pause(false);
- }
- void pcm_play_dma_stop(void)
- {
- /* NOTE: due to how pcm_play_get_more_callback() works, this is
- * possibly called from pcmSamplesToByteArray(), i.e. another thread.
- * => We need to discover the env_ptr */
- JNIEnv* env = getJavaEnvironment();
- (*env)->CallVoidMethod(env,
- RockboxPCM_instance,
- stop_method);
- }
- void pcm_play_dma_pause(bool pause)
- {
- (*env_ptr)->CallVoidMethod(env_ptr,
- RockboxPCM_instance,
- play_pause_method,
- (int)pause);
- }
- size_t pcm_get_bytes_waiting(void)
- {
- return pcm_data_size;
- }
- const void * pcm_play_dma_get_peak_buffer(int *count)
- {
- uintptr_t addr = (uintptr_t)pcm_data_start;
- *count = pcm_data_size / 4;
- return (void *)((addr + 3) & ~3);
- }
- void pcm_play_dma_init(void)
- {
- /* in order to have background music playing after leaving the activity,
- * we need to allocate the PCM object from the Rockbox thread (the Activity
- * runs in a separate thread because it would otherwise kill us when
- * stopping it)
- *
- * Luckily we only reference the PCM object from here, so it's safe (and
- * clean) to allocate it here
- **/
- JNIEnv e = *env_ptr;
- /* get the class and its constructor */
- RockboxPCM_class = e->FindClass(env_ptr, "org/rockbox/RockboxPCM");
- jmethodID constructor = e->GetMethodID(env_ptr, RockboxPCM_class, "<init>", "()V");
- /* instance = new RockboxPCM() */
- RockboxPCM_instance = e->NewObject(env_ptr, RockboxPCM_class, constructor);
- /* cache needed methods */
- play_pause_method = e->GetMethodID(env_ptr, RockboxPCM_class, "play_pause", "(Z)V");
- set_volume_method = e->GetMethodID(env_ptr, RockboxPCM_class, "set_volume", "(I)V");
- stop_method = e->GetMethodID(env_ptr, RockboxPCM_class, "stop", "()V");
- }
- void pcm_postinit(void)
- {
- }
- void pcm_set_mixer_volume(int volume)
- {
- (*env_ptr)->CallVoidMethod(env_ptr, RockboxPCM_instance, set_volume_method, volume);
- }
- /*
- * release audio resources */
- void pcm_shutdown(void)
- {
- JNIEnv e = *env_ptr;
- jmethodID release = e->GetMethodID(env_ptr, RockboxPCM_class, "release", "()V");
- e->CallVoidMethod(env_ptr, RockboxPCM_instance, release);
- }
- /* Due to limitations of default_event_handler(), parameters gets swallowed when
- * being posted with queue_broadcast(), so workaround this by caching the last
- * value.
- */
- static int lastPostedVolume = -1;
- int hosted_get_volume(void)
- {
- return lastPostedVolume;
- }
- JNIEXPORT void JNICALL
- Java_org_rockbox_RockboxPCM_postVolumeChangedEvent(JNIEnv *env,
- jobject this,
- jint volume)
- {
- (void) env;
- (void) this;
- if (volume != lastPostedVolume)
- {
- lastPostedVolume = volume;
- queue_broadcast(SYS_VOLUME_CHANGED, 0);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement