jack2 supports android devices & rebase current changes to mastertags/v1.9.10
| @@ -0,0 +1,251 @@ | |||
| #define LOG_TAG "JAMSHMSERVICE" | |||
| #include <stddef.h> | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <unistd.h> | |||
| #include <binder/MemoryHeapBase.h> | |||
| #include <binder/IServiceManager.h> | |||
| #include <binder/IPCThreadState.h> | |||
| #include <utils/Log.h> | |||
| #include <sys/stat.h> | |||
| #include <sys/socket.h> | |||
| #include <sys/types.h> | |||
| #include <sys/un.h> | |||
| #include <sys/wait.h> | |||
| #include "BnAndroidShm.h" | |||
| #include "AndroidShm.h" | |||
| #include "JackConstants.h" | |||
| #include <fcntl.h> | |||
| #include <signal.h> | |||
| #include <limits.h> | |||
| #include <errno.h> | |||
| #include <dirent.h> | |||
| #include <sys/mman.h> | |||
| #include <linux/ashmem.h> | |||
| #include <cutils/ashmem.h> | |||
| #include "JackError.h" | |||
| #include <semaphore.h> | |||
| #define MEMORY_SIZE 10*1024 | |||
| #define SEMAPHORE_NULL_CHAR '\0' | |||
| // remove ALOGI log | |||
| #undef ALOGI | |||
| #define ALOGI | |||
| namespace android { | |||
| int AndroidShm::instantiate() { | |||
| defaultServiceManager()->addService(String16("com.samsung.android.jam.IAndroidShm"), new AndroidShm); // SINGLETON WITH SAME NAME | |||
| return 0; | |||
| } | |||
| int AndroidShm::sendCommand(const char* command) { | |||
| ALOGI("I(pid:%d) send command is %s\n", getpid(), command); | |||
| if(strcmp(command, "semaphore") == 0) { | |||
| // print debug message about semaphore simulation | |||
| for(int i = MAX_SEMAPHORE_MEMORY_COUNT -1 ; i >= 0; i--) { | |||
| printf("index[%3d] = ptr[%p] name[%s]\n", i, (mSemaphore[i] != NULL)?mSemaphore[i]->getBase():0, mSemaphoreName[i]); | |||
| ALOGI("index[%3d] = ptr[%p] name[%s]\n", i, (mSemaphore[i] != NULL)?mSemaphore[i]->getBase():0, mSemaphoreName[i]); | |||
| } | |||
| } | |||
| return NO_ERROR; | |||
| } | |||
| int AndroidShm::testGetBufferByNewProcess() { | |||
| ALOGI("testGetBufferByNewProcess..."); | |||
| int status; | |||
| int childPid = fork(); | |||
| if(childPid > 0) { | |||
| ALOGI("I(pid%d) made a child process(pid:%d)", getpid(), childPid); | |||
| ALOGI("I(pid%d) wait until child(%d) was finish", getpid(), childPid); | |||
| wait(&status); | |||
| // wait 하지 않으면 child process가 남아 있음. | |||
| ALOGI("child(%d) was finished. ", childPid); | |||
| } else if(childPid == 0) { | |||
| ALOGI("im a new child process(pid:%d) ", getpid()); | |||
| if(-1 == execlp("/system/bin/getbufferclient","getbufferclient",NULL)) { | |||
| ALOGE("failed to execute getbufferclient"); | |||
| } | |||
| exit(0); | |||
| } else { | |||
| ALOGI("failed creating child process"); | |||
| } | |||
| return 0; | |||
| } | |||
| int AndroidShm::testGetBuffer() { | |||
| ALOGI("I(pid:%d) trying to test get buffer...", getpid()); | |||
| sp<IServiceManager> sm = defaultServiceManager(); | |||
| ALOGI("get default ServiceManager is done"); | |||
| sp<IBinder> b; | |||
| //String16* serviceName = new String16("com.samsung.android.jam.IAndroidShm"); | |||
| do { | |||
| //ALOGI("here"); | |||
| b = sm->getService(String16("com.samsung.android.jam.IAndroidShm")); | |||
| //ALOGI("getservice is done"); | |||
| if(b != 0) | |||
| break; | |||
| //ALOGI("AndroidShm is not working, waiting..."); | |||
| usleep(500000); | |||
| } while(true); | |||
| sp<IAndroidShm> service = interface_cast<IAndroidShm>(b); | |||
| //shared buffer. | |||
| sp<IMemoryHeap> receiverMemBase = service->getBuffer(0); | |||
| unsigned int *base = (unsigned int *) receiverMemBase->getBase(); | |||
| int ret = 0; | |||
| if(base != (unsigned int *) -1) { | |||
| ALOGD("AndroidShm::testGetBuffer base=%p Data=0x%x\n",base, *base); | |||
| *base = (*base)+1; | |||
| ret = (unsigned int)(*base); | |||
| ALOGI("AndroidShm::testGetBuffer base=%p Data=0x%x CHANGED\n",base, *base); | |||
| receiverMemBase = 0; | |||
| } else { | |||
| ALOGE("Error shared memory not available\n"); | |||
| } | |||
| return 0; | |||
| } | |||
| sp<IMemoryHeap> AndroidShm::getBuffer(int index) { | |||
| ALOGI("I(pid:%d) getBuffer index:%d", getpid(), index); | |||
| if(index < 0 || index >= MAX_SHARED_MEMORY_COUNT) { | |||
| ALOGE("error : out of index [%d]", index); | |||
| return NULL; | |||
| } | |||
| return mMemHeap[index]; | |||
| } | |||
| int AndroidShm::MemAlloc(unsigned int size) { | |||
| ALOGI("try to allocate memory size[%d]", size); | |||
| for(int i = 0; i < MAX_SHARED_MEMORY_COUNT; i++) { | |||
| if(mMemHeap[i] == NULL) { | |||
| mMemHeap[i] = new MemoryHeapBase(size); | |||
| if(mMemHeap[i] == NULL){ | |||
| ALOGI("fail to alloc, try one more..."); | |||
| continue; // try one more. | |||
| } | |||
| return i; | |||
| } | |||
| } | |||
| ALOGE("fail to MemAlloc"); | |||
| return -1; // fail to alloc | |||
| } | |||
| AndroidShm::AndroidShm() { | |||
| ALOGI("AndroidShm is created"); | |||
| for(int i = 0; i < MAX_SHARED_MEMORY_COUNT; i++) { | |||
| mMemHeap[i] = NULL; | |||
| } | |||
| mRegistryIndex = 10000; | |||
| //mMemHeap = new MemoryHeapBase(MEMORY_SIZE); | |||
| //unsigned int *base = (unsigned int*) mMemHeap->getBase(); | |||
| //*base = 0xdeadcafe;// | |||
| for(int j = 0; j < MAX_SEMAPHORE_MEMORY_COUNT; j++) { | |||
| mSemaphore[j] = NULL; | |||
| memset(mSemaphoreName[j], SEMAPHORE_NULL_CHAR, MAX_SEMAPHORE_NAME_LENGTH); | |||
| } | |||
| } | |||
| AndroidShm::~AndroidShm() { | |||
| ALOGI("AndroidShm is destroyed"); | |||
| for(int i = 0; i < MAX_SHARED_MEMORY_COUNT; i++) { | |||
| (mMemHeap[i]).clear(); | |||
| } | |||
| for(int j = 0; j < MAX_SEMAPHORE_MEMORY_COUNT; j++) { | |||
| (mSemaphore[j]).clear(); | |||
| } | |||
| } | |||
| //status_t AndroidShm::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { | |||
| // return BnAndroidShm::onTransact(code, data, reply, flags); | |||
| //} | |||
| int AndroidShm::allocShm(const int size) { // if negative return value is error | |||
| ALOGI("try to alloc shared memory size[%d]", size); | |||
| return MemAlloc(size); | |||
| } | |||
| int AndroidShm::removeShm(const unsigned int index) { // shared memory 제거 | |||
| ALOGI("try to remove shared memory index[%d]", index); | |||
| if(index >= MAX_SHARED_MEMORY_COUNT) { | |||
| ALOGE("remove shared memory: out of index"); | |||
| return -1; | |||
| } | |||
| (mMemHeap[index]).clear(); | |||
| return 1; | |||
| } | |||
| int AndroidShm::isAllocated(const unsigned int index) { // allocated 여부 확인 | |||
| ALOGI("try to check the memory allocation index[%d]", index); | |||
| if(index >= MAX_SHARED_MEMORY_COUNT) { | |||
| ALOGE("shared memory: out of index"); | |||
| return 0; | |||
| } | |||
| if(mMemHeap[index] == NULL) | |||
| return 0; | |||
| else | |||
| return 1; | |||
| } | |||
| int AndroidShm::setRegistryIndex(const unsigned int index) { | |||
| ALOGI("set registry index %d", index); | |||
| mRegistryIndex = index; | |||
| return 1; | |||
| } | |||
| int AndroidShm::getRegistryIndex() { | |||
| return mRegistryIndex; | |||
| } | |||
| sp<IMemoryHeap> AndroidShm::InitSemaphore(const char* name) { | |||
| ALOGI("init semaphore [%s]", name); | |||
| for(int i = 0; i < MAX_SEMAPHORE_MEMORY_COUNT; i++) { | |||
| if(mSemaphoreName[i][0] == SEMAPHORE_NULL_CHAR) { | |||
| mSemaphore[i] = new MemoryHeapBase(sizeof(sem_t)); | |||
| if(mSemaphore[i] == NULL){ | |||
| ALOGI("fail to alloc, try one more..."); | |||
| continue; | |||
| } | |||
| if(sem_init((sem_t*)(mSemaphore[i]->getBase()), 1, 0) == 0) { | |||
| strncpy(mSemaphoreName[i], name, MAX_SEMAPHORE_NAME_LENGTH - 1); | |||
| mSemaphoreName[i][MAX_SEMAPHORE_NAME_LENGTH - 1] = '\0'; | |||
| ALOGI("sem_init success"); | |||
| return mSemaphore[i]; | |||
| } else { | |||
| (mSemaphore[i]).clear(); | |||
| ALOGE("sem_init failed null returned"); | |||
| return NULL; | |||
| } | |||
| } else { | |||
| // find already exist name | |||
| if(strcmp(mSemaphoreName[i], name) == 0) { // found | |||
| ALOGI("found - return alread allocated semaphore"); | |||
| return mSemaphore[i]; | |||
| } | |||
| } | |||
| } | |||
| ALOGE("sem_init failed null returned 2"); | |||
| return NULL; | |||
| } | |||
| }; | |||
| @@ -0,0 +1,51 @@ | |||
| #ifndef ANDROIDSHM | |||
| #define ANDROIDSHM | |||
| #include <binder/Parcel.h> | |||
| #include "BnAndroidShm.h" | |||
| #include <utils/Log.h> | |||
| #include <binder/MemoryHeapBase.h> | |||
| #include "shm.h" | |||
| #include "android/Shm.h" //android extension of shm.h | |||
| namespace android { | |||
| class AndroidShm : public BnAndroidShm | |||
| { | |||
| #define MAX_SHARED_MEMORY_COUNT 257 | |||
| private: | |||
| int MemAlloc(unsigned int size); | |||
| public: | |||
| virtual ~AndroidShm(); | |||
| static int instantiate(); | |||
| virtual int sendCommand(const char* command); | |||
| virtual int allocShm(const int size); // if negative return value is error | |||
| virtual int removeShm(const unsigned int index); // shared memory Á¦°Å | |||
| virtual int isAllocated(const unsigned int index); // allocated ¿©ºÎ È®ÀÎ | |||
| virtual int setRegistryIndex(const unsigned int index); | |||
| virtual int getRegistryIndex(); | |||
| virtual sp<IMemoryHeap> InitSemaphore(const char* name); | |||
| virtual sp<IMemoryHeap> getBuffer(int index); | |||
| //virtual status_t onTransact( | |||
| // uint32_t code, | |||
| // const Parcel& data, | |||
| // Parcel* reply, | |||
| // uint32_t flags); | |||
| private: | |||
| int testGetBuffer(); | |||
| int testGetBufferByNewProcess(); | |||
| AndroidShm(); | |||
| sp<MemoryHeapBase> mMemHeap[MAX_SHARED_MEMORY_COUNT]; | |||
| unsigned int mRegistryIndex; | |||
| // for named semaphore simulation | |||
| #define MAX_SEMAPHORE_MEMORY_COUNT 300 | |||
| #define MAX_SEMAPHORE_NAME_LENGTH 300 | |||
| sp<MemoryHeapBase> mSemaphore[MAX_SEMAPHORE_MEMORY_COUNT]; | |||
| char mSemaphoreName[MAX_SEMAPHORE_MEMORY_COUNT][MAX_SEMAPHORE_NAME_LENGTH]; | |||
| }; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,19 @@ | |||
| #define LOG_TAG "main_androidshmservice" | |||
| #include <binder/IPCThreadState.h> | |||
| #include <binder/ProcessState.h> | |||
| #include <binder/IServiceManager.h> | |||
| #include <utils/Log.h> | |||
| #include "../../common/shm.h" | |||
| #include "../Shm.h" //android extension of shm.h | |||
| using namespace android; | |||
| int main(int argc, char *argv[]) { | |||
| jack_instantiate(); | |||
| ProcessState::self()->startThreadPool(); | |||
| ALOGI("AndroidShmService is starting now"); | |||
| IPCThreadState::self()->joinThreadPool(); | |||
| return 0; | |||
| } | |||
| @@ -0,0 +1,23 @@ | |||
| IAndroidShm의 기능을 테스트 하기 위한 용도로 사용되는 프로그램입니다. | |||
| AndroidShm은 service manager에 shared memory를 할당해주는 서비스입니다. | |||
| service name: com.sec.apa.IAndroidShm | |||
| 실행 파일: | |||
| /system/bin/androidshmservice | |||
| ------------------------------------------- | |||
| ./test | |||
| AndroidShmService를 테스트하는 프로그램 | |||
| /system/bin/shmservicetest | |||
| AndroidShmService에서 제공하는 기능을 UnitTest합니다. | |||
| 동작 확인 방법: | |||
| adb logcat 으로 로그로 성공/실패 확인함. | |||
| 전제 조건: | |||
| /system/bin/androidshmservice를 실행중인 상태이어야 합니다. | |||
| @@ -0,0 +1,177 @@ | |||
| #include "../../IAndroidShm.h" | |||
| #include <binder/MemoryHeapBase.h> | |||
| #include <binder/IServiceManager.h> | |||
| #include "../../../common/shm.h" | |||
| namespace android { | |||
| static sp<IMemoryHeap> receiverMemBase; | |||
| #define MAX_SHARED_MEMORY_COUNT 257 | |||
| sp<IAndroidShm> getAndroidShmService() { | |||
| sp<IAndroidShm> shm = 0; | |||
| /* Get the buffer service */ | |||
| if (shm == NULL) { | |||
| sp<IServiceManager> sm = defaultServiceManager(); | |||
| sp<IBinder> binder; | |||
| binder = sm->getService(String16("com.samsung.android.jam.IAndroidShm")); | |||
| if (binder != 0) { | |||
| shm = IAndroidShm::asInterface(binder); | |||
| //shm = interface_cast<IAndroidShm>(binder); | |||
| } | |||
| } | |||
| return shm; | |||
| } | |||
| unsigned int * getBufferMemPointer(int index) | |||
| { | |||
| sp<IAndroidShm> shm = getAndroidShmService(); | |||
| if (shm == NULL) { | |||
| printf("The EneaBufferServer is not published\n"); | |||
| return (unsigned int *)-1; /* return an errorcode... */ | |||
| } else { | |||
| receiverMemBase = shm->getBuffer(index); | |||
| if(receiverMemBase != NULL) | |||
| return (unsigned int *) receiverMemBase->getBase(); | |||
| else | |||
| return (unsigned int*)-1; | |||
| } | |||
| } | |||
| } | |||
| using namespace android; | |||
| void showStatus() { | |||
| sp<IAndroidShm> shm = getAndroidShmService(); | |||
| if(shm == NULL) { | |||
| printf("shm service is not available\n"); | |||
| return; | |||
| } | |||
| printf("<<<<<<<<<<< dump memory allocation status >>>>>>>>>>\n"); | |||
| for(int i = 256; i >= 0; i--) { | |||
| if(shm->isAllocated(i) == 1) { | |||
| printf("Mem[%3d] == 0x%x\n", i, (unsigned int)getBufferMemPointer(i)); | |||
| } else { | |||
| printf("Mem[%3d] == NULL\n", i); | |||
| } | |||
| } | |||
| } | |||
| void showRegistryIndex() { | |||
| sp<IAndroidShm> shm = getAndroidShmService(); | |||
| if(shm == NULL) { | |||
| printf("shm service is not available\n"); | |||
| return; | |||
| } | |||
| printf("<<<<<<<<<<< show registry index >>>>>>>>>>\n"); | |||
| printf("index [%3d]\n",shm->getRegistryIndex()); | |||
| } | |||
| void showHeader() { | |||
| sp<IAndroidShm> shm = getAndroidShmService(); | |||
| if(shm == NULL) { | |||
| printf("shm service is not available\n"); | |||
| return; | |||
| } | |||
| if(shm->getRegistryIndex() > 256) { | |||
| printf("don't have a registry header\n"); | |||
| return; | |||
| } | |||
| unsigned int* buffer = getBufferMemPointer(shm->getRegistryIndex()); | |||
| if(buffer) { | |||
| jack_shm_header_t * header = (jack_shm_header_t*)buffer; | |||
| printf("<<<<<<<<<< register header value >>>>>>>>>>\n"); | |||
| printf("memory address 0x%x 0x%x\n", (unsigned int)(header), (unsigned int)buffer); | |||
| printf("magic = %d\n", header->magic); | |||
| printf("protocol = %d\n", header->protocol); | |||
| printf("type = %d\n", header->type); | |||
| printf("size = %d\n", header->size); | |||
| printf("hdr_len = %d\n", header->hdr_len); | |||
| printf("entry_len = %d\n", header->entry_len); | |||
| for(int j = 0; j < MAX_SERVERS; j++) { | |||
| //char name[256]; | |||
| //memset(name, '\0', 256); | |||
| //strncpy(name, header->server[j].name, 10); | |||
| printf("server[%d] pid = %d, name = %s\n", j, header->server[j].pid, header->server[j].name); | |||
| } | |||
| } | |||
| } | |||
| void showBody() { | |||
| sp<IAndroidShm> shm = getAndroidShmService(); | |||
| if(shm == NULL) { | |||
| printf("shm service is not available\n"); | |||
| return; | |||
| } | |||
| if(shm->getRegistryIndex() > 256) { | |||
| printf("don't have a registry body\n"); | |||
| return; | |||
| } | |||
| unsigned int* buffer = getBufferMemPointer(shm->getRegistryIndex()); | |||
| if(buffer) { | |||
| jack_shm_header_t * header = (jack_shm_header_t*)buffer; | |||
| printf("<<<<<<<<<< registry body value >>>>>>>>>>\n"); | |||
| jack_shm_registry_t * registry = (jack_shm_registry_t *) (header + 1); | |||
| for(int k = 255; k >= 0; k--) { | |||
| printf("registry[%3d] index[%3d],allocator[%3d],size[%6d],id[%10s],fd[%3d]\n", k, | |||
| registry[k].index, registry[k].allocator, registry[k].size, | |||
| registry[k].id, | |||
| registry[k].fd); | |||
| } | |||
| } | |||
| } | |||
| void showSemaphore() { | |||
| sp<IAndroidShm> shm = getAndroidShmService(); | |||
| if(shm == NULL) { | |||
| printf("shm service is not available\n"); | |||
| return; | |||
| } | |||
| shm->sendCommand("semaphore"); | |||
| printf("log will be shown in the logcat log\n"); | |||
| } | |||
| int main(int argc, char** argv) { | |||
| // base could be on same address as Servers base but this | |||
| // is purely by luck do NEVER rely on this. Linux memory | |||
| // management may put it wherever it likes. | |||
| if(argc < 2) { | |||
| printf("usage\n shmservicedump [status|header|body|index|semaphore]\n"); | |||
| printf(" status: show the shared memory allocation status\n"); | |||
| printf(" header: show the registry header infomations if the registry exist\n"); | |||
| printf(" body: show the registry body infomations if the registry exist\n"); | |||
| printf(" index: show the index of array that is allocated registry shared memory\n"); | |||
| printf(" semaphore: show the memory array about semaphore simulation\n"); | |||
| return 0; | |||
| } | |||
| if(strcmp(argv[1], "semaphore") == 0) { | |||
| showSemaphore(); | |||
| } else if(strcmp(argv[1], "index") == 0) { | |||
| showRegistryIndex(); | |||
| } else if(strcmp(argv[1], "status") == 0) { | |||
| showStatus(); | |||
| } else if(strcmp(argv[1], "header") == 0) { | |||
| showHeader(); | |||
| } else if(strcmp(argv[1], "body") == 0) { | |||
| showBody(); | |||
| } else { | |||
| printf("%s is invalid parameter\n", argv[1]); | |||
| } | |||
| return 0; | |||
| } | |||
| @@ -0,0 +1,189 @@ | |||
| #include "../../IAndroidShm.h" | |||
| #include <binder/MemoryHeapBase.h> | |||
| #include <binder/IServiceManager.h> | |||
| namespace android { | |||
| static sp<IMemoryHeap> receiverMemBase; | |||
| #define MAX_SHARED_MEMORY_COUNT 257 | |||
| sp<IAndroidShm> getAndroidShmService() { | |||
| sp<IAndroidShm> shm = 0; | |||
| /* Get the buffer service */ | |||
| if (shm == NULL) { | |||
| sp<IServiceManager> sm = defaultServiceManager(); | |||
| sp<IBinder> binder; | |||
| binder = sm->getService(String16("com.samsung.android.jam.IAndroidShm")); | |||
| if (binder != 0) { | |||
| shm = IAndroidShm::asInterface(binder); | |||
| //shm = interface_cast<IAndroidShm>(binder); | |||
| } | |||
| } | |||
| return shm; | |||
| } | |||
| unsigned int * getBufferMemPointer(int index) { | |||
| sp<IAndroidShm> shm = getAndroidShmService(); | |||
| if (shm == NULL) { | |||
| ALOGE("The EneaBufferServer is not published"); | |||
| return (unsigned int *)-1; /* return an errorcode... */ | |||
| } else { | |||
| receiverMemBase = shm->getBuffer(index); | |||
| if(receiverMemBase != NULL) | |||
| return (unsigned int *) receiverMemBase->getBase(); | |||
| else | |||
| return (unsigned int*)-1; | |||
| } | |||
| } | |||
| } | |||
| using namespace android; | |||
| void setup_test() { | |||
| sp<IAndroidShm> shm = getAndroidShmService(); | |||
| if(shm == NULL) return; | |||
| for(int i = 0; i < MAX_SHARED_MEMORY_COUNT; i++) { | |||
| shm->removeShm(i); | |||
| } | |||
| } | |||
| void teardown_test() { | |||
| } | |||
| void increase_value_once() { | |||
| ALOGD("*****test: increase_value_once*****\n"); | |||
| sp<IAndroidShm> shm = getAndroidShmService(); | |||
| if(shm == NULL) return; | |||
| int slot = shm->allocShm(10000); | |||
| unsigned int *base = getBufferMemPointer(slot); | |||
| if(base != (unsigned int *)-1) { | |||
| ALOGD("ShmServiceTest base=%p Data=0x%x\n",base, *base); | |||
| *base = (*base)+1; | |||
| ALOGD("ShmServiceTest base=%p Data=0x%x CHANGED\n",base, *base); | |||
| //receiverMemBase = 0; | |||
| } else { | |||
| ALOGE("Error shared memory not available\n"); | |||
| } | |||
| } | |||
| void increase_value_10times() { | |||
| ALOGD("*****test: increase_value_10times*****\n"); | |||
| sp<IAndroidShm> shm = getAndroidShmService(); | |||
| if(shm == NULL) return; | |||
| int slot = shm->allocShm(10000); | |||
| for(int i = 0; i < 10; i++) { | |||
| unsigned int *base = getBufferMemPointer(slot); | |||
| if(base != (unsigned int *)-1) { | |||
| ALOGD("ShmServiceTest base=%p Data=0x%x\n",base, *base); | |||
| *base = (*base)+1; | |||
| ALOGD("ShmServiceTest base=%p Data=0x%x CHANGED\n",base, *base); | |||
| //receiverMemBase = 0; | |||
| } else { | |||
| ALOGE("Error shared memory not available\n"); | |||
| } | |||
| } | |||
| } | |||
| void check_allocated() { | |||
| ALOGD("*****test: check_allocated*****\n"); | |||
| sp<IAndroidShm> shm = getAndroidShmService(); | |||
| if(shm == NULL) return; | |||
| int slot = shm->allocShm(10000); | |||
| int i = 0; | |||
| for(; i < MAX_SHARED_MEMORY_COUNT; i++) { | |||
| if(slot == i) { | |||
| if(shm->isAllocated(i) == 1) { | |||
| //ALOGD("pass\n"); | |||
| } else { | |||
| ALOGD("failed\n"); | |||
| } | |||
| } else { | |||
| if(shm->isAllocated(i) == 0) { | |||
| //ALOGD("pass\n"); | |||
| } else { | |||
| ALOGD("failed\n"); | |||
| } | |||
| } | |||
| } | |||
| if(i == MAX_SHARED_MEMORY_COUNT) { | |||
| ALOGD("pass\n"); | |||
| } | |||
| } | |||
| void test_set_get_registry_index() { | |||
| ALOGD("*****test: test_set_get_registry_index*****\n"); | |||
| sp<IAndroidShm> shm = getAndroidShmService(); | |||
| if(shm == NULL) return; | |||
| int registry = 1; | |||
| shm->setRegistryIndex(registry); | |||
| if(registry == shm->getRegistryIndex()) { | |||
| ALOGD("pass\n"); | |||
| } else { | |||
| ALOGD("fail\n"); | |||
| } | |||
| registry = 0; | |||
| shm->setRegistryIndex(registry); | |||
| if(registry == shm->getRegistryIndex()) { | |||
| ALOGD("pass\n"); | |||
| } else { | |||
| ALOGD("fail\n"); | |||
| } | |||
| } | |||
| void test_memset() { | |||
| ALOGD("*****test: test_memset*****\n"); | |||
| sp<IAndroidShm> shm = getAndroidShmService(); | |||
| if(shm == NULL) return; | |||
| int slot = shm->allocShm(10000); | |||
| unsigned int * pnt = getBufferMemPointer(slot); | |||
| memset (pnt, 0, 10000); | |||
| ALOGD("result : 0 0 0 0\n"); | |||
| ALOGD("memory dump : %d %d %d %d\n", pnt[0], pnt[1], pnt[2], pnt[3]); | |||
| memset (pnt, 0xffffffff, 10000); | |||
| ALOGD("result : -1 -1 -1 -1\n"); | |||
| ALOGD("memory dump : %d %d %d %d", pnt[0], pnt[1], pnt[2], pnt[3]); | |||
| } | |||
| int main(int argc, char** argv) { | |||
| // base could be on same address as Servers base but this | |||
| // is purely by luck do NEVER rely on this. Linux memory | |||
| // management may put it wherever it likes. | |||
| setup_test(); | |||
| increase_value_once(); | |||
| teardown_test(); | |||
| setup_test(); | |||
| increase_value_10times(); | |||
| teardown_test(); | |||
| setup_test(); | |||
| check_allocated(); | |||
| teardown_test(); | |||
| setup_test(); | |||
| test_set_get_registry_index(); | |||
| teardown_test(); | |||
| setup_test(); | |||
| test_memset(); | |||
| teardown_test(); | |||
| return 0; | |||
| } | |||
| @@ -0,0 +1,83 @@ | |||
| #include "BnAndroidShm.h" | |||
| #include <binder/Parcel.h> | |||
| namespace android { | |||
| status_t BnAndroidShm::onTransact( uint32_t code, | |||
| const Parcel &data, | |||
| Parcel *reply, | |||
| uint32_t flags) | |||
| { | |||
| switch(code) { | |||
| case HW_SENDCOMMAND:{ | |||
| CHECK_INTERFACE(IAndroidShm, data, reply); | |||
| const char *str; | |||
| str = data.readCString(); | |||
| reply->writeInt32(sendCommand(str)); | |||
| return NO_ERROR; | |||
| }break; | |||
| case HW_GETBUFFER:{ | |||
| CHECK_INTERFACE(IAndroidShm, data, reply); | |||
| int32_t index; | |||
| data.readInt32(&index); | |||
| sp<IMemoryHeap> Data = getBuffer(index); | |||
| if(Data != NULL){ | |||
| reply->writeStrongBinder(Data->asBinder()); | |||
| } | |||
| return NO_ERROR; | |||
| }break; | |||
| case HW_ALLOC_SHM:{ | |||
| CHECK_INTERFACE(IAndroidShm, data, reply); | |||
| int32_t size; | |||
| data.readInt32(&size); | |||
| reply->writeInt32(allocShm(size)); | |||
| return NO_ERROR; | |||
| }break; | |||
| case HW_REMOVE_SHM:{ | |||
| CHECK_INTERFACE(IAndroidShm, data, reply); | |||
| int32_t index; | |||
| data.readInt32(&index); | |||
| reply->writeInt32(removeShm(index)); | |||
| return NO_ERROR; | |||
| }break; | |||
| case HW_IS_ALLOCATED:{ | |||
| CHECK_INTERFACE(IAndroidShm, data, reply); | |||
| int32_t index; | |||
| data.readInt32(&index); | |||
| reply->writeInt32(isAllocated(index)); | |||
| return NO_ERROR; | |||
| }break; | |||
| case HW_SET_REGISTRY_INDEX:{ | |||
| CHECK_INTERFACE(IAndroidShm, data, reply); | |||
| int32_t index; | |||
| data.readInt32(&index); | |||
| reply->writeInt32(setRegistryIndex(index)); | |||
| return NO_ERROR; | |||
| }break; | |||
| case HW_GET_REGISTRY_INDEX:{ | |||
| CHECK_INTERFACE(IAndroidShm, data, reply); | |||
| reply->writeInt32(getRegistryIndex()); | |||
| return NO_ERROR; | |||
| }break; | |||
| case HW_INIT_SEMAPHORE:{ | |||
| CHECK_INTERFACE(IAndroidShm, data, reply); | |||
| const char *name; | |||
| name = data.readCString(); | |||
| sp<IMemoryHeap> Data = InitSemaphore(name); | |||
| if(Data != NULL){ | |||
| reply->writeStrongBinder(Data->asBinder()); | |||
| } | |||
| return NO_ERROR; | |||
| }break; | |||
| default: | |||
| return BBinder::onTransact(code, data, reply, flags); | |||
| } | |||
| } | |||
| }; | |||
| @@ -0,0 +1,16 @@ | |||
| #ifndef BNANDROIDSHM | |||
| #define BNANDROIDSHM | |||
| #include <binder/Parcel.h> | |||
| #include "IAndroidShm.h" | |||
| namespace android { | |||
| class BnAndroidShm : public BnInterface<IAndroidShm> { | |||
| public: | |||
| virtual status_t onTransact( uint32_t code, | |||
| const Parcel& data, | |||
| Parcel* reply, | |||
| uint32_t flags = 0); | |||
| }; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,111 @@ | |||
| #include <binder/Parcel.h> | |||
| #include <utils/Log.h> | |||
| #include "BpAndroidShm.h" | |||
| namespace android{ | |||
| int BpAndroidShm::sendCommand(const char*command) { | |||
| Parcel data, reply; | |||
| data.writeInterfaceToken( | |||
| IAndroidShm::getInterfaceDescriptor()); | |||
| data.writeCString(command); | |||
| status_t status = remote()->transact(HW_SENDCOMMAND, data, &reply); | |||
| if(status != NO_ERROR) { | |||
| ALOGE("print sendCommand error: %s", strerror(-status)); | |||
| } else { | |||
| status= reply.readInt32(); | |||
| } | |||
| return status; | |||
| } | |||
| sp<IMemoryHeap> BpAndroidShm::getBuffer(int index) { | |||
| Parcel data, reply; | |||
| sp<IMemoryHeap> memHeap = NULL; | |||
| data.writeInterfaceToken(IAndroidShm::getInterfaceDescriptor()); | |||
| data.writeInt32(index); | |||
| remote()->transact(HW_GETBUFFER, data, &reply); | |||
| memHeap = interface_cast<IMemoryHeap> (reply.readStrongBinder()); | |||
| return memHeap; | |||
| } | |||
| BpAndroidShm::BpAndroidShm( const sp<IBinder>& impl) | |||
| : BpInterface<IAndroidShm>(impl) | |||
| {} | |||
| BpAndroidShm::~BpAndroidShm() | |||
| {} | |||
| int BpAndroidShm::allocShm(const int size) { // if negative return value is error | |||
| Parcel data, reply; | |||
| data.writeInterfaceToken(IAndroidShm::getInterfaceDescriptor()); | |||
| data.writeInt32(size); | |||
| status_t status = remote()->transact(HW_ALLOC_SHM, data, &reply); | |||
| if(status != NO_ERROR) { | |||
| ALOGE("print allocShm error: %s", strerror(-status)); | |||
| } else { | |||
| status= reply.readInt32(); | |||
| } | |||
| return status; | |||
| } | |||
| int BpAndroidShm::removeShm(const unsigned int index) { // shared memory Á¦°Å | |||
| Parcel data, reply; | |||
| data.writeInterfaceToken(IAndroidShm::getInterfaceDescriptor()); | |||
| data.writeInt32(index); | |||
| status_t status = remote()->transact(HW_REMOVE_SHM, data, &reply); | |||
| if(status != NO_ERROR) { | |||
| ALOGE("print removeShm error: %s", strerror(-status)); | |||
| } else { | |||
| status= reply.readInt32(); | |||
| } | |||
| return status; | |||
| } | |||
| int BpAndroidShm::isAllocated(const unsigned int index) { // allocated ¿©ºÎ È®ÀÎ | |||
| Parcel data, reply; | |||
| data.writeInterfaceToken(IAndroidShm::getInterfaceDescriptor()); | |||
| data.writeInt32(index); | |||
| status_t status = remote()->transact(HW_IS_ALLOCATED, data, &reply); | |||
| if(status != NO_ERROR) { | |||
| ALOGE("print isAllocated error: %s", strerror(-status)); | |||
| } else { | |||
| status= reply.readInt32(); | |||
| } | |||
| return status; | |||
| } | |||
| int BpAndroidShm::setRegistryIndex(const unsigned int index) { | |||
| Parcel data, reply; | |||
| data.writeInterfaceToken(IAndroidShm::getInterfaceDescriptor()); | |||
| data.writeInt32(index); | |||
| status_t status = remote()->transact(HW_SET_REGISTRY_INDEX, data, &reply); | |||
| if(status != NO_ERROR) { | |||
| ALOGE("print setRegistryIndex error: %s", strerror(-status)); | |||
| } else { | |||
| status= reply.readInt32(); | |||
| } | |||
| return status; | |||
| } | |||
| int BpAndroidShm::getRegistryIndex() { | |||
| Parcel data, reply; | |||
| data.writeInterfaceToken(IAndroidShm::getInterfaceDescriptor()); | |||
| status_t status = remote()->transact(HW_GET_REGISTRY_INDEX, data, &reply); | |||
| if(status != NO_ERROR) { | |||
| ALOGE("print getRegistryIndex error: %s", strerror(-status)); | |||
| } else { | |||
| status= reply.readInt32(); | |||
| } | |||
| return status; | |||
| } | |||
| sp<IMemoryHeap> BpAndroidShm::InitSemaphore(const char* name) { | |||
| Parcel data, reply; | |||
| sp<IMemoryHeap> memHeap = NULL; | |||
| data.writeInterfaceToken(IAndroidShm::getInterfaceDescriptor()); | |||
| data.writeCString(name); | |||
| status_t status = remote()->transact(HW_INIT_SEMAPHORE, data, &reply); | |||
| memHeap = interface_cast<IMemoryHeap> (reply.readStrongBinder()); | |||
| return memHeap; | |||
| } | |||
| }; | |||
| @@ -0,0 +1,25 @@ | |||
| #ifndef BPANDROIDSHM | |||
| #define BPANDROIDSHM | |||
| #include <binder/Parcel.h> | |||
| #include "IAndroidShm.h" | |||
| #include <binder/IMemory.h> | |||
| namespace android { | |||
| class BpAndroidShm: public BpInterface<IAndroidShm> { | |||
| public: | |||
| BpAndroidShm( const sp<IBinder> & impl); | |||
| virtual ~BpAndroidShm(); | |||
| virtual sp<IMemoryHeap> getBuffer(int index); | |||
| virtual int sendCommand(const char *command); | |||
| virtual int allocShm(const int size); // if negative return value is error | |||
| virtual int removeShm(const unsigned int index); // shared memory Á¦°Å | |||
| virtual int isAllocated(const unsigned int index); // allocated ¿©ºÎ È®ÀÎ | |||
| virtual int setRegistryIndex(const unsigned int index); | |||
| virtual int getRegistryIndex(); | |||
| virtual sp<IMemoryHeap> InitSemaphore(const char* name); | |||
| }; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,66 @@ | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/common) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/alsa_in_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/alsa_out_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/androidshmservice_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/shmservicetest_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/shmservicedump_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_samplerate_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_freewheel_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_connect_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_disconnect_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_latent_client_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_midiseq_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_zombie_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_lsp_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_load_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jackd_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_monitor_client_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_simple_looper_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_simple_client_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_cpu_load_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_iodelay_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_midisine_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_cpu_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_simple_keyboard_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_unload_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_wait_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_alias_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_metro_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_bufsize_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_thru_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_session_notify_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_midi_latency_test_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_rec_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_netsource_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_net_master_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_net_slave_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_showtime_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_server_control_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_evmon_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_test_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_transport_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_simple_session_client_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_simple_effect_intermediates) | |||
| $(call add_clean_step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_multiple_metro_intermediates) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/jack_midi_dump_intermediates) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/common) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/posix) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libjack_intermediates) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libjacknet_intermediates) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libjackserver_intermediates) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libjackshm_intermediates) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/jack_alsa_intermediates) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/jack_dummy_intermediates) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/jack_net_intermediates) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/jack_loopback_intermediates) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/jack_netone_intermediates) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/audioadapter_intermediates) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/example_lib_intermediates) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/netadapter_intermediates) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/netmanager_intermediates) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/profiler_intermediates) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/jack_goldfish_intermediates) | |||
| $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/jack_opensles_intermediates) | |||
| @@ -0,0 +1,6 @@ | |||
| #include "IAndroidShm.h" | |||
| #include "BpAndroidShm.h" | |||
| namespace android{ | |||
| IMPLEMENT_META_INTERFACE(AndroidShm, "com.samsung.android.jam.IAndroidShm"); | |||
| }; | |||
| @@ -0,0 +1,41 @@ | |||
| #ifndef IANDROIDSHM | |||
| #define IANDROIDSHM | |||
| #include <binder/IInterface.h> | |||
| #include <binder/IMemory.h> | |||
| namespace android { | |||
| enum { | |||
| HW_GETBUFFER = IBinder::FIRST_CALL_TRANSACTION, | |||
| HW_MULTIPLY, | |||
| HW_STARTSERVER, | |||
| HW_MAKECLIENT, | |||
| HW_SENDCOMMAND, | |||
| HW_LOADSO, | |||
| HW_ALLOC_SHM, | |||
| HW_REMOVE_SHM, | |||
| HW_IS_ALLOCATED, | |||
| HW_SET_REGISTRY_INDEX, | |||
| HW_GET_REGISTRY_INDEX, | |||
| HW_INIT_SEMAPHORE | |||
| }; | |||
| class IAndroidShm: public IInterface { | |||
| public: | |||
| DECLARE_META_INTERFACE(AndroidShm); | |||
| virtual sp<IMemoryHeap> getBuffer(int index) = 0; | |||
| virtual int sendCommand(const char *command) = 0; | |||
| virtual int allocShm(const int size) = 0; // if negative return value is error | |||
| virtual int removeShm(const unsigned int index) = 0; // shared memory Á¦°Å | |||
| virtual int isAllocated(const unsigned int index) = 0; // allocated ¿©ºÎ È®ÀÎ | |||
| virtual int setRegistryIndex(const unsigned int index) = 0; | |||
| virtual int getRegistryIndex() = 0; | |||
| // for named semaphore simulation | |||
| virtual sp<IMemoryHeap> InitSemaphore(const char* name) = 0; | |||
| }; | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,262 @@ | |||
| /* | |||
| Copyright (C) 2004-2008 Grame | |||
| Copyright (C) 2013 Samsung Electronics | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU Lesser General Public License as published by | |||
| the Free Software Foundation; either version 2.1 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| #include "JackAndroidSemaphore.h" | |||
| #include "JackTools.h" | |||
| #include "JackConstants.h" | |||
| #include "JackError.h" | |||
| #include <fcntl.h> | |||
| #include <stdio.h> | |||
| #include <sys/time.h> | |||
| #include "IAndroidShm.h" | |||
| #include "shm.h" | |||
| #include "android/Shm.h" //android extension of shm.h | |||
| namespace Jack | |||
| { | |||
| pthread_mutex_t JackAndroidSemaphore::mutex = PTHREAD_MUTEX_INITIALIZER; | |||
| void JackAndroidSemaphore::BuildName(const char* client_name, const char* server_name, char* res, int size) | |||
| { | |||
| char ext_client_name[SYNC_MAX_NAME_SIZE + 1]; | |||
| JackTools::RewriteName(client_name, ext_client_name); | |||
| if (getenv("JACK_PROMISCUOUS_SERVER")) { | |||
| snprintf(res, size, "jack_sem.%s_%s", server_name, ext_client_name); | |||
| } else { | |||
| snprintf(res, size, "jack_sem.%d_%s_%s", JackTools::GetUID(), server_name, ext_client_name); | |||
| } | |||
| } | |||
| bool JackAndroidSemaphore::Signal() | |||
| { | |||
| int res; | |||
| if (!fSemaphore) { | |||
| jack_error("JackAndroidSemaphore::Signal name = %s already deallocated!!", fName); | |||
| return false; | |||
| } | |||
| if (fFlush) | |||
| return true; | |||
| if ((res = sem_post(fSemaphore)) != 0) { | |||
| jack_error("JackAndroidSemaphore::Signal name = %s err = %s", fName, strerror(errno)); | |||
| } | |||
| return (res == 0); | |||
| } | |||
| bool JackAndroidSemaphore::SignalAll() | |||
| { | |||
| int res; | |||
| if (!fSemaphore) { | |||
| jack_error("JackAndroidSemaphore::SignalAll name = %s already deallocated!!", fName); | |||
| return false; | |||
| } | |||
| if (fFlush) | |||
| return true; | |||
| if ((res = sem_post(fSemaphore)) != 0) { | |||
| jack_error("JackAndroidSemaphore::SignalAll name = %s err = %s", fName, strerror(errno)); | |||
| } | |||
| return (res == 0); | |||
| } | |||
| /* | |||
| bool JackAndroidSemaphore::Wait() | |||
| { | |||
| int res; | |||
| if (!fSemaphore) { | |||
| jack_error("JackAndroidSemaphore::Wait name = %s already deallocated!!", fName); | |||
| return false; | |||
| } | |||
| if ((res = sem_wait(fSemaphore)) != 0) { | |||
| jack_error("JackAndroidSemaphore::Wait name = %s err = %s", fName, strerror(errno)); | |||
| } | |||
| return (res == 0); | |||
| } | |||
| */ | |||
| bool JackAndroidSemaphore::Wait() | |||
| { | |||
| int res; | |||
| while ((res = sem_wait(fSemaphore) < 0)) { | |||
| jack_error("JackAndroidSemaphore::Wait name = %s err = %s", fName, strerror(errno)); | |||
| if (errno != EINTR) { | |||
| break; | |||
| } | |||
| } | |||
| return (res == 0); | |||
| } | |||
| bool JackAndroidSemaphore::TimedWait(long usec) | |||
| { | |||
| int res; | |||
| struct timeval now; | |||
| timespec time; | |||
| if (!fSemaphore) { | |||
| jack_error("JackAndroidSemaphore::TimedWait name = %s already deallocated!!", fName); | |||
| return false; | |||
| } | |||
| gettimeofday(&now, 0); | |||
| time.tv_sec = now.tv_sec + usec / 1000000; | |||
| long tv_usec = (now.tv_usec + (usec % 1000000)); | |||
| time.tv_sec += tv_usec / 1000000; | |||
| time.tv_nsec = (tv_usec % 1000000) * 1000; | |||
| while ((res = sem_timedwait(fSemaphore, &time)) < 0) { | |||
| jack_error("JackAndroidSemaphore::TimedWait err = %s", strerror(errno)); | |||
| jack_log("JackAndroidSemaphore::TimedWait now : %ld %ld ", now.tv_sec, now.tv_usec); | |||
| jack_log("JackAndroidSemaphore::TimedWait next : %ld %ld ", time.tv_sec, time.tv_nsec/1000); | |||
| if (errno == ETIMEDOUT) { | |||
| timespec ts; | |||
| clock_gettime(CLOCK_REALTIME, &ts); | |||
| ts.tv_sec = time.tv_sec - ts.tv_sec; | |||
| ts.tv_nsec = time.tv_nsec - ts.tv_nsec; | |||
| if (ts.tv_nsec < 0) { | |||
| ts.tv_nsec += 1000000000; | |||
| ts.tv_sec -= 1; | |||
| } | |||
| if (ts.tv_sec < 0 || ts.tv_nsec < 0) { | |||
| jack_error("JackAndroidSemaphore::TimedWait time may changed or client killed already! wait again!"); | |||
| gettimeofday(&now, 0); | |||
| time.tv_sec = now.tv_sec + usec / 1000000; | |||
| long tv_usec = (now.tv_usec + (usec % 1000000)); | |||
| time.tv_sec += tv_usec / 1000000; | |||
| time.tv_nsec = (tv_usec % 1000000) * 1000; | |||
| if ((res = sem_timedwait(fSemaphore, &time)) < 0) { | |||
| jack_error("JackAndroidSemaphore::TimedWait err = %s", strerror(errno)); | |||
| jack_log("JackAndroidSemaphore::TimedWait now : %ld %ld ", now.tv_sec, now.tv_usec); | |||
| jack_log("JackAndroidSemaphore::TimedWait next : %ld %ld ", time.tv_sec, time.tv_nsec/1000); | |||
| } | |||
| } | |||
| } | |||
| if (errno != EINTR) { | |||
| break; | |||
| } | |||
| } | |||
| return (res == 0); | |||
| } | |||
| // Server side : publish the semaphore in the global namespace | |||
| bool JackAndroidSemaphore::Allocate(const char* name, const char* server_name, int value) | |||
| { | |||
| pthread_mutex_lock (&mutex); | |||
| BuildName(name, server_name, fName, sizeof(fName)); | |||
| jack_log("JackAndroidSemaphore::Allocate name = %s val = %ld", fName, value); | |||
| android::sp<android::IAndroidShm> service = android::Shm::getShmService(); | |||
| if(service == NULL){ | |||
| jack_error("shm service is null"); | |||
| return false; | |||
| } | |||
| fSemaphoreMemory = service->InitSemaphore(fName); | |||
| if(fSemaphoreMemory != NULL){ | |||
| fSemaphore = (sem_t*)(fSemaphoreMemory->getBase()); | |||
| } | |||
| if(fSemaphore == NULL) { | |||
| jack_error("Allocate: can't check in named semaphore name = %s err = %s", fName, strerror(errno)); | |||
| pthread_mutex_unlock (&mutex); | |||
| return false; | |||
| } else { | |||
| sem_init(fSemaphore, 1, 0); | |||
| jack_log("sem_init()"); | |||
| pthread_mutex_unlock (&mutex); | |||
| return true; | |||
| } | |||
| } | |||
| // Client side : get the published semaphore from server | |||
| bool JackAndroidSemaphore::ConnectInput(const char* name, const char* server_name) | |||
| { | |||
| pthread_mutex_lock (&mutex); | |||
| BuildName(name, server_name, fName, sizeof(fName)); | |||
| jack_log("JackAndroidSemaphore::Connect name = %s", fName); | |||
| // Temporary... | |||
| if (fSemaphore) { | |||
| jack_log("Already connected name = %s", name); | |||
| pthread_mutex_unlock (&mutex); | |||
| return true; | |||
| } | |||
| android::sp<android::IAndroidShm> service = android::Shm::getShmService(); | |||
| if(service == NULL){ | |||
| jack_error("shm service is null"); | |||
| return false; | |||
| } | |||
| fSemaphoreMemory = service->InitSemaphore(fName); | |||
| if(fSemaphoreMemory != NULL){ | |||
| fSemaphore = (sem_t*)(fSemaphoreMemory->getBase()); | |||
| } | |||
| if(fSemaphore == NULL) { | |||
| jack_error("Connect: can't connect named semaphore name = %s err = %s", fName, strerror(errno)); | |||
| pthread_mutex_unlock (&mutex); | |||
| return false; | |||
| } else { | |||
| int val = 0; | |||
| sem_getvalue(fSemaphore, &val); | |||
| jack_log("JackAndroidSemaphore::Connect sem_getvalue %ld", val); | |||
| pthread_mutex_unlock (&mutex); | |||
| return true; | |||
| } | |||
| } | |||
| bool JackAndroidSemaphore::Connect(const char* name, const char* server_name) | |||
| { | |||
| return ConnectInput(name, server_name); | |||
| } | |||
| bool JackAndroidSemaphore::ConnectOutput(const char* name, const char* server_name) | |||
| { | |||
| return ConnectInput(name, server_name); | |||
| } | |||
| bool JackAndroidSemaphore::Disconnect() | |||
| { | |||
| if (fSemaphore) { | |||
| jack_log("JackAndroidSemaphore::Disconnect name = %s", fName); | |||
| fSemaphore = NULL; | |||
| } | |||
| return true; | |||
| } | |||
| // Server side : destroy the semaphore | |||
| void JackAndroidSemaphore::Destroy() | |||
| { | |||
| if (fSemaphore != NULL) { | |||
| jack_log("JackAndroidSemaphore::Disconnect name = %s", fName); | |||
| fSemaphore = NULL; | |||
| } else { | |||
| jack_error("JackAndroidSemaphore::Destroy semaphore == NULL"); | |||
| } | |||
| } | |||
| } // end of namespace | |||
| @@ -0,0 +1,76 @@ | |||
| /* | |||
| Copyright (C) 2004-2008 Grame | |||
| Copyright (C) 2013 Samsung Electronics | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU Lesser General Public License as published by | |||
| the Free Software Foundation; either version 2.1 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| #ifndef __JackAndroidSemaphore__ | |||
| #define __JackAndroidSemaphore__ | |||
| #include "JackSynchro.h" | |||
| #include "JackCompilerDeps.h" | |||
| #include <semaphore.h> | |||
| #include <time.h> | |||
| #include <assert.h> | |||
| #include <binder/IMemory.h> | |||
| #include <binder/MemoryHeapBase.h> | |||
| #include <utils/RefBase.h> | |||
| namespace Jack | |||
| { | |||
| /*! | |||
| \brief Inter process synchronization using POSIX semaphore. | |||
| */ | |||
| class SERVER_EXPORT JackAndroidSemaphore : public detail::JackSynchro | |||
| { | |||
| private: | |||
| sem_t* fSemaphore; | |||
| android::sp<android::IMemoryHeap> fSemaphoreMemory; | |||
| static pthread_mutex_t mutex; | |||
| protected: | |||
| void BuildName(const char* name, const char* server_name, char* res, int size); | |||
| public: | |||
| JackAndroidSemaphore():JackSynchro(), fSemaphore(NULL) | |||
| {} | |||
| bool Signal(); | |||
| bool SignalAll(); | |||
| bool Wait(); | |||
| bool TimedWait(long usec); | |||
| bool Allocate(const char* name, const char* server_name, int value); | |||
| bool Connect(const char* name, const char* server_name); | |||
| bool ConnectInput(const char* name, const char* server_name); | |||
| bool ConnectOutput(const char* name, const char* server_name); | |||
| bool Disconnect(); | |||
| void Destroy(); | |||
| }; | |||
| } // end of namespace | |||
| #endif | |||
| @@ -0,0 +1,374 @@ | |||
| /* | |||
| Copyright (C) 2001 Paul Davis | |||
| Copyright (C) 2004-2008 Grame | |||
| Copyright (C) 2013 Samsung Electronics | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU Lesser General Public License as published by | |||
| the Free Software Foundation; either version 2.1 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| #include "JackAndroidThread.h" | |||
| #include "JackError.h" | |||
| #include "JackTime.h" | |||
| #include "JackGlobals.h" | |||
| #include <string.h> // for memset | |||
| #include <unistd.h> // for _POSIX_PRIORITY_SCHEDULING check | |||
| #include <signal.h> | |||
| //#define JACK_SCHED_POLICY SCHED_RR | |||
| #define JACK_SCHED_POLICY SCHED_FIFO | |||
| namespace Jack | |||
| { | |||
| void JackAndroidThread::thread_exit_handler(int sig) | |||
| { | |||
| printf("this signal is %d \n", sig); | |||
| pthread_exit(0); | |||
| } | |||
| void* JackAndroidThread::ThreadHandler(void* arg) | |||
| { | |||
| JackAndroidThread* obj = (JackAndroidThread*)arg; | |||
| JackRunnableInterface* runnable = obj->fRunnable; | |||
| int err; | |||
| struct sigaction actions; | |||
| memset(&actions, 0, sizeof(actions)); | |||
| sigemptyset(&actions.sa_mask); | |||
| actions.sa_flags = 0; | |||
| actions.sa_handler = thread_exit_handler; | |||
| sigaction(SIGUSR1,&actions,NULL); | |||
| // Signal creation thread when started with StartSync | |||
| jack_log("JackAndroidThread::ThreadHandler : start"); | |||
| obj->fStatus = kIniting; | |||
| // Call Init method | |||
| if (!runnable->Init()) { | |||
| jack_error("Thread init fails: thread quits"); | |||
| return 0; | |||
| } | |||
| obj->fStatus = kRunning; | |||
| // If Init succeed, start the thread loop | |||
| bool res = true; | |||
| while (obj->fStatus == kRunning && res) { | |||
| res = runnable->Execute(); | |||
| } | |||
| jack_log("JackAndroidThread::ThreadHandler : exit"); | |||
| pthread_exit(0); | |||
| return 0; // never reached | |||
| } | |||
| int JackAndroidThread::Start() | |||
| { | |||
| fStatus = kStarting; | |||
| // Check if the thread was correctly started | |||
| if (StartImp(&fThread, fPriority, fRealTime, ThreadHandler, this) < 0) { | |||
| fStatus = kIdle; | |||
| return -1; | |||
| } else { | |||
| return 0; | |||
| } | |||
| } | |||
| int JackAndroidThread::StartSync() | |||
| { | |||
| fStatus = kStarting; | |||
| if (StartImp(&fThread, fPriority, fRealTime, ThreadHandler, this) < 0) { | |||
| fStatus = kIdle; | |||
| return -1; | |||
| } else { | |||
| int count = 0; | |||
| while (fStatus == kStarting && ++count < 1000) { | |||
| JackSleep(1000); | |||
| } | |||
| return (count == 1000) ? -1 : 0; | |||
| } | |||
| } | |||
| int JackAndroidThread::StartImp(jack_native_thread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg) | |||
| { | |||
| pthread_attr_t attributes; | |||
| struct sched_param rt_param; | |||
| pthread_attr_init(&attributes); | |||
| int res; | |||
| if ((res = pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_JOINABLE))) { | |||
| jack_error("Cannot request joinable thread creation for thread res = %d", res); | |||
| return -1; | |||
| } | |||
| if ((res = pthread_attr_setscope(&attributes, PTHREAD_SCOPE_SYSTEM))) { | |||
| jack_error("Cannot set scheduling scope for thread res = %d", res); | |||
| return -1; | |||
| } | |||
| if (realtime) { | |||
| jack_log("JackAndroidThread::StartImp : create RT thread"); | |||
| if ((res = pthread_attr_setschedpolicy(&attributes, JACK_SCHED_POLICY))) { | |||
| jack_error("Cannot set RR scheduling class for RT thread res = %d", res); | |||
| return -1; | |||
| } | |||
| memset(&rt_param, 0, sizeof(rt_param)); | |||
| rt_param.sched_priority = priority; | |||
| if ((res = pthread_attr_setschedparam(&attributes, &rt_param))) { | |||
| jack_error("Cannot set scheduling priority for RT thread res = %d", res); | |||
| return -1; | |||
| } | |||
| } else { | |||
| jack_log("JackAndroidThread::StartImp : create non RT thread"); | |||
| } | |||
| if ((res = pthread_attr_setstacksize(&attributes, THREAD_STACK))) { | |||
| jack_error("Cannot set thread stack size res = %d", res); | |||
| return -1; | |||
| } | |||
| if ((res = JackGlobals::fJackThreadCreator(thread, &attributes, start_routine, arg))) { | |||
| jack_error("Cannot create thread res = %d", res); | |||
| return -1; | |||
| } | |||
| pthread_attr_destroy(&attributes); | |||
| return 0; | |||
| } | |||
| int JackAndroidThread::Kill() | |||
| { | |||
| if (fThread != (jack_native_thread_t)NULL) { // If thread has been started | |||
| jack_log("JackAndroidThread::Kill"); | |||
| void* status; | |||
| pthread_kill(fThread, SIGUSR1); | |||
| pthread_join(fThread, &status); | |||
| fStatus = kIdle; | |||
| fThread = (jack_native_thread_t)NULL; | |||
| return 0; | |||
| } else { | |||
| return -1; | |||
| } | |||
| } | |||
| int JackAndroidThread::Stop() | |||
| { | |||
| if (fThread != (jack_native_thread_t)NULL) { // If thread has been started | |||
| jack_log("JackAndroidThread::Stop"); | |||
| void* status; | |||
| fStatus = kIdle; // Request for the thread to stop | |||
| pthread_join(fThread, &status); | |||
| fThread = (jack_native_thread_t)NULL; | |||
| return 0; | |||
| } else { | |||
| return -1; | |||
| } | |||
| } | |||
| int JackAndroidThread::KillImp(jack_native_thread_t thread) | |||
| { | |||
| if (thread != (jack_native_thread_t)NULL) { // If thread has been started | |||
| jack_log("JackAndroidThread::Kill"); | |||
| void* status; | |||
| pthread_kill(thread, SIGUSR1); | |||
| pthread_join(thread, &status); | |||
| return 0; | |||
| } else { | |||
| return -1; | |||
| } | |||
| } | |||
| int JackAndroidThread::StopImp(jack_native_thread_t thread) | |||
| { | |||
| if (thread != (jack_native_thread_t)NULL) { // If thread has been started | |||
| jack_log("JackAndroidThread::Stop"); | |||
| void* status; | |||
| pthread_join(thread, &status); | |||
| return 0; | |||
| } else { | |||
| return -1; | |||
| } | |||
| } | |||
| int JackAndroidThread::AcquireRealTime() | |||
| { | |||
| return (fThread != (jack_native_thread_t)NULL) ? AcquireRealTimeImp(fThread, fPriority) : -1; | |||
| } | |||
| int JackAndroidThread::AcquireSelfRealTime() | |||
| { | |||
| return AcquireRealTimeImp(pthread_self(), fPriority); | |||
| } | |||
| int JackAndroidThread::AcquireRealTime(int priority) | |||
| { | |||
| fPriority = priority; | |||
| return AcquireRealTime(); | |||
| } | |||
| int JackAndroidThread::AcquireSelfRealTime(int priority) | |||
| { | |||
| fPriority = priority; | |||
| return AcquireSelfRealTime(); | |||
| } | |||
| int JackAndroidThread::AcquireRealTimeImp(jack_native_thread_t thread, int priority) | |||
| { | |||
| struct sched_param rtparam; | |||
| int res; | |||
| memset(&rtparam, 0, sizeof(rtparam)); | |||
| rtparam.sched_priority = priority; | |||
| jack_log("JackAndroidThread::AcquireRealTimeImp priority = %d", priority); | |||
| if ((res = pthread_setschedparam(thread, JACK_SCHED_POLICY, &rtparam)) != 0) { | |||
| jack_error("Cannot use real-time scheduling (RR/%d)" | |||
| "(%d: %s)", rtparam.sched_priority, res, | |||
| strerror(res)); | |||
| return -1; | |||
| } | |||
| return 0; | |||
| } | |||
| int JackAndroidThread::DropRealTime() | |||
| { | |||
| return (fThread != (jack_native_thread_t)NULL) ? DropRealTimeImp(fThread) : -1; | |||
| } | |||
| int JackAndroidThread::DropSelfRealTime() | |||
| { | |||
| return DropRealTimeImp(pthread_self()); | |||
| } | |||
| int JackAndroidThread::DropRealTimeImp(jack_native_thread_t thread) | |||
| { | |||
| struct sched_param rtparam; | |||
| int res; | |||
| memset(&rtparam, 0, sizeof(rtparam)); | |||
| rtparam.sched_priority = 0; | |||
| if ((res = pthread_setschedparam(thread, SCHED_OTHER, &rtparam)) != 0) { | |||
| jack_error("Cannot switch to normal scheduling priority(%s)", strerror(errno)); | |||
| return -1; | |||
| } | |||
| return 0; | |||
| } | |||
| jack_native_thread_t JackAndroidThread::GetThreadID() | |||
| { | |||
| return fThread; | |||
| } | |||
| bool JackAndroidThread::IsThread() | |||
| { | |||
| return pthread_self() == fThread; | |||
| } | |||
| void JackAndroidThread::Terminate() | |||
| { | |||
| jack_log("JackAndroidThread::Terminate"); | |||
| pthread_exit(0); | |||
| } | |||
| SERVER_EXPORT void ThreadExit() | |||
| { | |||
| jack_log("ThreadExit"); | |||
| pthread_exit(0); | |||
| } | |||
| } // end of namespace | |||
| bool jack_get_thread_realtime_priority_range(int * min_ptr, int * max_ptr) | |||
| { | |||
| #if defined(_POSIX_PRIORITY_SCHEDULING) && !defined(__APPLE__) | |||
| int min, max; | |||
| min = sched_get_priority_min(JACK_SCHED_POLICY); | |||
| if (min == -1) | |||
| { | |||
| jack_error("sched_get_priority_min() failed."); | |||
| return false; | |||
| } | |||
| max = sched_get_priority_max(JACK_SCHED_POLICY); | |||
| if (max == -1) | |||
| { | |||
| jack_error("sched_get_priority_max() failed."); | |||
| return false; | |||
| } | |||
| *min_ptr = min; | |||
| *max_ptr = max; | |||
| return true; | |||
| #else | |||
| return false; | |||
| #endif | |||
| } | |||
| bool jack_tls_allocate_key(jack_tls_key *key_ptr) | |||
| { | |||
| int ret; | |||
| ret = pthread_key_create(key_ptr, NULL); | |||
| if (ret != 0) | |||
| { | |||
| jack_error("pthread_key_create() failed with error %d", ret); | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| bool jack_tls_free_key(jack_tls_key key) | |||
| { | |||
| int ret; | |||
| ret = pthread_key_delete(key); | |||
| if (ret != 0) | |||
| { | |||
| jack_error("pthread_key_delete() failed with error %d", ret); | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| bool jack_tls_set(jack_tls_key key, void *data_ptr) | |||
| { | |||
| int ret; | |||
| ret = pthread_setspecific(key, (const void *)data_ptr); | |||
| if (ret != 0) | |||
| { | |||
| jack_error("pthread_setspecific() failed with error %d", ret); | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| void *jack_tls_get(jack_tls_key key) | |||
| { | |||
| return pthread_getspecific(key); | |||
| } | |||
| @@ -0,0 +1,97 @@ | |||
| /* | |||
| Copyright (C) 2001 Paul Davis | |||
| Copyright (C) 2004-2008 Grame | |||
| Copyright (C) 2013 Samsung Electronics | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU Lesser General Public License as published by | |||
| the Free Software Foundation; either version 2.1 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| #ifndef __JackAndroidThread__ | |||
| #define __JackAndroidThread__ | |||
| #include "JackThread.h" | |||
| #include <pthread.h> | |||
| namespace Jack | |||
| { | |||
| /* use 512KB stack per thread - the default is way too high to be feasible | |||
| * with mlockall() on many systems */ | |||
| #define THREAD_STACK 524288 | |||
| enum | |||
| { | |||
| PTHREAD_CANCEL_DEFERRED, | |||
| PTHREAD_CANCEL_ASYNCHRONOUS | |||
| }; | |||
| /*! | |||
| \brief The POSIX thread base class. | |||
| */ | |||
| class SERVER_EXPORT JackAndroidThread : public detail::JackThreadInterface | |||
| { | |||
| protected: | |||
| jack_native_thread_t fThread; | |||
| static void* ThreadHandler(void* arg); | |||
| static void thread_exit_handler(int sig); | |||
| public: | |||
| JackAndroidThread(JackRunnableInterface* runnable, bool real_time, int priority, int cancellation) | |||
| : JackThreadInterface(runnable, priority, real_time, cancellation), fThread((jack_native_thread_t)NULL) | |||
| {} | |||
| JackAndroidThread(JackRunnableInterface* runnable, int cancellation = PTHREAD_CANCEL_ASYNCHRONOUS) | |||
| : JackThreadInterface(runnable, 0, false, cancellation), fThread((jack_native_thread_t)NULL) | |||
| {} | |||
| int Start(); | |||
| int StartSync(); | |||
| int Kill(); | |||
| int Stop(); | |||
| void Terminate(); | |||
| int AcquireRealTime(); // Used when called from another thread | |||
| int AcquireSelfRealTime(); // Used when called from thread itself | |||
| int AcquireRealTime(int priority); // Used when called from another thread | |||
| int AcquireSelfRealTime(int priority); // Used when called from thread itself | |||
| int DropRealTime(); // Used when called from another thread | |||
| int DropSelfRealTime(); // Used when called from thread itself | |||
| jack_native_thread_t GetThreadID(); | |||
| bool IsThread(); | |||
| static int AcquireRealTimeImp(jack_native_thread_t thread, int priority); | |||
| static int AcquireRealTimeImp(jack_native_thread_t thread, int priority, UInt64 period, UInt64 computation, UInt64 constraint) | |||
| { | |||
| return JackAndroidThread::AcquireRealTimeImp(thread, priority); | |||
| } | |||
| static int DropRealTimeImp(jack_native_thread_t thread); | |||
| static int StartImp(jack_native_thread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg); | |||
| static int StopImp(jack_native_thread_t thread); | |||
| static int KillImp(jack_native_thread_t thread); | |||
| }; | |||
| SERVER_EXPORT void ThreadExit(); | |||
| } // end of namespace | |||
| #endif | |||
| @@ -0,0 +1,42 @@ | |||
| /* | |||
| Copyright (C) 2004-2008 Grame | |||
| Copyright (C) 2013 Samsung Electronics | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU Lesser General Public License as published by | |||
| the Free Software Foundation; either version 2.1 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| #ifndef __JackAtomic_android__ | |||
| #define __JackAtomic_android__ | |||
| #include "JackTypes.h" | |||
| #include <sys/atomics.h> | |||
| static inline char CAS(volatile UInt32 value, UInt32 newvalue, volatile void* addr) | |||
| { | |||
| #if 1 | |||
| return !__atomic_cmpxchg(value, newvalue, (volatile int *)addr); | |||
| #else | |||
| //slow compare_and_swap_32 | |||
| if (*(UInt32*)addr == value) { | |||
| *(UInt32*)addr = newvalue; | |||
| return true; | |||
| } | |||
| return false; | |||
| #endif | |||
| } | |||
| #endif | |||
| @@ -0,0 +1,48 @@ | |||
| /* | |||
| Copyright (C) 2004-2008 Grame | |||
| Copyright (C) 2013 Samsung Electronics | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU Lesser General Public License as published by | |||
| the Free Software Foundation; either version 2.1 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| #ifndef __JackCompilerDeps_android__ | |||
| #define __JackCompilerDeps_android__ | |||
| #include "JackConstants.h" | |||
| #if __GNUC__ | |||
| #define MEM_ALIGN(x,y) x __attribute__((aligned(y))) | |||
| #define LIB_EXPORT __attribute__((visibility("default"))) | |||
| #ifdef SERVER_SIDE | |||
| #if (__GNUC__< 4) | |||
| #define SERVER_EXPORT | |||
| #else | |||
| #define SERVER_EXPORT __attribute__((visibility("default"))) | |||
| #endif | |||
| #else | |||
| #define SERVER_EXPORT __attribute__((visibility("hidden"))) | |||
| #endif | |||
| #else | |||
| #define MEM_ALIGN(x,y) x | |||
| #define LIB_EXPORT | |||
| #define SERVER_EXPORT | |||
| /* Add other things here for non-gcc platforms */ | |||
| #endif | |||
| #endif /* __JackCompilerDeps_android__ */ | |||
| @@ -0,0 +1,89 @@ | |||
| // u/* -*- Mode: C++ ; c-basic-offset: 4 -*- */ | |||
| /* | |||
| JACK control API implementation | |||
| Copyright (C) 2008 Nedko Arnaudov | |||
| Copyright (C) 2008 Grame | |||
| Copyright (C) 2013 Samsung Electronics | |||
| 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; version 2 of the License. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| */ | |||
| #ifndef WIN32 | |||
| #include <stdint.h> | |||
| #include <dirent.h> | |||
| #include <pthread.h> | |||
| #endif | |||
| #include "types.h" | |||
| #include <string.h> | |||
| #include <errno.h> | |||
| #include <stdio.h> | |||
| #include <assert.h> | |||
| #include <signal.h> | |||
| #include "JackControlAPIAndroid.h" | |||
| #include "JackConstants.h" | |||
| #include "JackServerGlobals.h" | |||
| using namespace Jack; | |||
| struct jackctl_sigmask | |||
| { | |||
| sigset_t signals; | |||
| }; | |||
| static jackctl_sigmask sigmask; | |||
| SERVER_EXPORT int | |||
| jackctl_wait_signals_and_return(jackctl_sigmask_t * sigmask) | |||
| { | |||
| int sig; | |||
| bool waiting = true; | |||
| while (waiting) { | |||
| #if defined(sun) && !defined(__sun__) // SUN compiler only, to check | |||
| sigwait(&sigmask->signals); | |||
| #else | |||
| sigwait(&sigmask->signals, &sig); | |||
| #endif | |||
| fprintf(stderr, "Jack main caught signal %d\n", sig); | |||
| switch (sig) { | |||
| case SIGUSR1: | |||
| //jack_dump_configuration(engine, 1); | |||
| break; | |||
| case SIGUSR2: | |||
| // driver exit | |||
| waiting = false; | |||
| break; | |||
| case SIGTTOU: | |||
| break; | |||
| default: | |||
| waiting = false; | |||
| break; | |||
| } | |||
| } | |||
| if (sig != SIGSEGV) { | |||
| // unblock signals so we can see them during shutdown. | |||
| // this will help prod developers not to lose sight of | |||
| // bugs that cause segfaults etc. during shutdown. | |||
| sigprocmask(SIG_UNBLOCK, &sigmask->signals, 0); | |||
| } | |||
| return sig; | |||
| } | |||
| @@ -0,0 +1,44 @@ | |||
| /* | |||
| JACK control API | |||
| Copyright (C) 2008 Nedko Arnaudov | |||
| Copyright (C) 2008 Grame | |||
| Copyright (C) 2013 Samsung Electronics | |||
| 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; version 2 of the License. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| */ | |||
| #ifndef __JackControlAPIAndroid__ | |||
| #define __JackControlAPIAndroid__ | |||
| #include "JackCompilerDeps.h" | |||
| /** opaque type for sigmask object */ | |||
| typedef struct jackctl_sigmask jackctl_sigmask_t; | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| SERVER_EXPORT int | |||
| jackctl_wait_signals_and_return( | |||
| jackctl_sigmask_t * signals); | |||
| #ifdef __cplusplus | |||
| } /* extern "C" */ | |||
| #endif | |||
| #endif | |||
| @@ -0,0 +1,153 @@ | |||
| /* | |||
| Copyright (C) 2001 Paul Davis | |||
| Copyright (C) 2004-2008 Grame | |||
| Copyright (C) 2008 Nedko Arnaudov | |||
| Copyright (C) 2013 Samsung Electronics | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU Lesser General Public License as published by | |||
| the Free Software Foundation; either version 2.1 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| #include <stdarg.h> | |||
| #include <stdio.h> | |||
| #include "JackError.h" | |||
| #include "JackGlobals.h" | |||
| #include "JackMessageBuffer.h" | |||
| #define LOG_BUF_SIZE 1024 | |||
| #undef LOG_TAG | |||
| #ifdef SERVER_SIDE | |||
| #define LOG_TAG "JackAudioServer" | |||
| #else | |||
| #define LOG_TAG "JackAudioClient" | |||
| #endif | |||
| #include <utils/Log.h> | |||
| using namespace Jack; | |||
| static bool change_thread_log_function(jack_log_function_t log_function) | |||
| { | |||
| return (jack_tls_get(JackGlobals::fKeyLogFunction) == NULL | |||
| && jack_tls_set(JackGlobals::fKeyLogFunction, (void*)log_function)); | |||
| } | |||
| SERVER_EXPORT int set_threaded_log_function() | |||
| { | |||
| return change_thread_log_function(JackMessageBufferAdd); | |||
| } | |||
| void jack_log_function(int level, const char *message) | |||
| { | |||
| void (* log_callback)(const char *); | |||
| switch (level) | |||
| { | |||
| case LOG_LEVEL_INFO: | |||
| log_callback = jack_info_callback; | |||
| break; | |||
| case LOG_LEVEL_ERROR: | |||
| log_callback = jack_error_callback; | |||
| break; | |||
| default: | |||
| return; | |||
| } | |||
| log_callback(message); | |||
| } | |||
| static void jack_format_and_log(int level, const char *prefix, const char *fmt, va_list ap) | |||
| { | |||
| char buffer[256]; | |||
| size_t len; | |||
| jack_log_function_t log_function; | |||
| if (prefix != NULL) { | |||
| len = strlen(prefix); | |||
| assert(len < 256); | |||
| memcpy(buffer, prefix, len); | |||
| } else { | |||
| len = 0; | |||
| } | |||
| vsnprintf(buffer + len, sizeof(buffer) - len, fmt, ap); | |||
| log_function = (jack_log_function_t)jack_tls_get(JackGlobals::fKeyLogFunction); | |||
| /* if log function is not overriden for thread, use default one */ | |||
| if (log_function == NULL) | |||
| { | |||
| log_function = jack_log_function; | |||
| //log_function(LOG_LEVEL_INFO, "------ Using default log function"); | |||
| } | |||
| else | |||
| { | |||
| //log_function(LOG_LEVEL_INFO, "++++++ Using thread-specific log function"); | |||
| } | |||
| log_function(level, buffer); | |||
| } | |||
| SERVER_EXPORT void jack_error(const char *fmt, ...) | |||
| { | |||
| va_list ap; | |||
| char buf[LOG_BUF_SIZE]; | |||
| va_start(ap, fmt); | |||
| vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); | |||
| va_end(ap); | |||
| __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, buf); | |||
| } | |||
| SERVER_EXPORT void jack_info(const char *fmt, ...) | |||
| { | |||
| va_list ap; | |||
| char buf[LOG_BUF_SIZE]; | |||
| va_start(ap, fmt); | |||
| vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); | |||
| va_end(ap); | |||
| __android_log_write(ANDROID_LOG_INFO, LOG_TAG, buf); | |||
| } | |||
| SERVER_EXPORT void jack_log(const char *fmt,...) | |||
| { | |||
| va_list ap; | |||
| char buf[LOG_BUF_SIZE]; | |||
| if (JackGlobals::fVerbose) { | |||
| va_start(ap, fmt); | |||
| vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); | |||
| va_end(ap); | |||
| __android_log_write(ANDROID_LOG_VERBOSE, LOG_TAG, buf); | |||
| } | |||
| } | |||
| SERVER_EXPORT void default_jack_error_callback(const char *desc) | |||
| { | |||
| fprintf(stderr, "%s\n", desc); | |||
| fflush(stderr); | |||
| } | |||
| SERVER_EXPORT void default_jack_info_callback(const char *desc) | |||
| { | |||
| fprintf(stdout, "%s\n", desc); | |||
| fflush(stdout); | |||
| } | |||
| SERVER_EXPORT void silent_jack_error_callback(const char *desc) | |||
| {} | |||
| SERVER_EXPORT void silent_jack_info_callback(const char *desc) | |||
| {} | |||
| SERVER_EXPORT void (*jack_error_callback)(const char *desc) = &default_jack_error_callback; | |||
| SERVER_EXPORT void (*jack_info_callback)(const char *desc) = &default_jack_info_callback; | |||
| @@ -0,0 +1,212 @@ | |||
| /* | |||
| Copyright (C) 2001 Paul Davis | |||
| Copyright (C) 2004-2008 Grame | |||
| Copyright (C) 2013 Samsung Electronics | |||
| 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 program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| */ | |||
| #include "JackGoldfishDriver.h" | |||
| #include "JackDriverLoader.h" | |||
| #include "JackThreadedDriver.h" | |||
| #include "JackEngineControl.h" | |||
| #include "JackGraphManager.h" | |||
| #include "JackCompilerDeps.h" | |||
| #include <iostream> | |||
| #include <unistd.h> | |||
| #include <fcntl.h> | |||
| #include <math.h> | |||
| #define JACK_GOLDFISH_BUFFER_SIZE 4096 | |||
| namespace Jack | |||
| { | |||
| static char const * const kAudioDeviceName = "/dev/eac"; | |||
| int JackGoldfishDriver::Open(jack_nframes_t buffer_size, | |||
| jack_nframes_t samplerate, | |||
| bool capturing, | |||
| bool playing, | |||
| int inchannels, | |||
| int outchannels, | |||
| bool monitor, | |||
| const char* capture_driver_uid, | |||
| const char* playback_driver_uid, | |||
| jack_nframes_t capture_latency, | |||
| jack_nframes_t playback_latency) { | |||
| jack_log("JackGoldfishDriver::Open"); | |||
| // Generic JackAudioDriver Open | |||
| if (JackAudioDriver::Open(buffer_size, samplerate, capturing, playing, inchannels, outchannels, monitor, | |||
| capture_driver_uid, playback_driver_uid, capture_latency, playback_latency) != 0) { | |||
| return -1; | |||
| } | |||
| mFd = ::open(kAudioDeviceName, O_RDWR); | |||
| jack_log("JackGoldfishDriver::Open(mFd=%d)", mFd); | |||
| if (!mBuffer) | |||
| mBuffer = (short *) malloc(sizeof(short) * JACK_GOLDFISH_BUFFER_SIZE * 2); | |||
| //JackAudioDriver::SetBufferSize(buffer_size); | |||
| //JackAudioDriver::SetSampleRate(samplerate); | |||
| return 0; | |||
| } | |||
| int JackGoldfishDriver::Close() { | |||
| jack_log("JackGoldfishDriver::Close"); | |||
| // Generic audio driver close | |||
| int res = JackAudioDriver::Close(); | |||
| if (mFd >= 0) ::close(mFd); | |||
| if (mBuffer) { | |||
| free(mBuffer); | |||
| mBuffer = NULL; | |||
| } | |||
| return res; | |||
| } | |||
| int JackGoldfishDriver::Read() { | |||
| jack_log("JackGoldfishDriver::Read"); | |||
| for (int i = 0; i < fCaptureChannels; i++) { | |||
| //silence | |||
| memset(GetInputBuffer(i), 0, sizeof(jack_default_audio_sample_t) * JACK_GOLDFISH_BUFFER_SIZE /* fEngineControl->fBufferSize */); | |||
| } | |||
| return 0; | |||
| } | |||
| int JackGoldfishDriver::Write() { | |||
| jack_log("JackGoldfishDriver::Write"); | |||
| //write(mFd, GetOutputBuffer(i), sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize); | |||
| jack_default_audio_sample_t* outputBuffer_1 = GetOutputBuffer(0); | |||
| jack_default_audio_sample_t* outputBuffer_2 = GetOutputBuffer(1); | |||
| for(int i=0, j=0; i<JACK_GOLDFISH_BUFFER_SIZE /* fEngineControl->fBufferSize */; i++) { | |||
| //convert float to short | |||
| *(mBuffer + j) = (short) (*(outputBuffer_1 + i) * 32640); j++; | |||
| *(mBuffer + j) = (short) (*(outputBuffer_2 + i) * 32640); j++; | |||
| } | |||
| write(mFd, mBuffer, sizeof(short) * JACK_GOLDFISH_BUFFER_SIZE * 2); | |||
| return 0; | |||
| } | |||
| int JackGoldfishDriver::SetBufferSize(jack_nframes_t buffer_size) { | |||
| jack_log("JackGoldfishDriver::SetBufferSize"); | |||
| JackAudioDriver::SetBufferSize(buffer_size); | |||
| return 0; | |||
| } | |||
| } // end of namespace | |||
| #ifdef __cplusplus | |||
| extern "C" | |||
| { | |||
| #endif | |||
| SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor () { | |||
| jack_driver_desc_t * desc; | |||
| jack_driver_desc_filler_t filler; | |||
| jack_driver_param_value_t value; | |||
| desc = jack_driver_descriptor_construct("goldfish", JackDriverMaster, "Timer based backend", &filler); | |||
| value.ui = 2U; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamUInt, &value, NULL, "Number of capture ports", NULL); | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "playback", 'P', JackDriverParamUInt, &value, NULL, "Number of playback ports", NULL); | |||
| value.ui = 44100U; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL); | |||
| value.i = 0; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "monitor", 'm', JackDriverParamBool, &value, NULL, "Provide monitor ports for the output", NULL); | |||
| value.ui = JACK_GOLDFISH_BUFFER_SIZE; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames per period", NULL); | |||
| value.ui = 21333U; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "wait", 'w', JackDriverParamUInt, &value, NULL, "Number of usecs to wait between engine processes", NULL); | |||
| return desc; | |||
| } | |||
| SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) { | |||
| jack_nframes_t sample_rate = 44100; | |||
| jack_nframes_t buffer_size = JACK_GOLDFISH_BUFFER_SIZE; | |||
| unsigned int capture_ports = 2; | |||
| unsigned int playback_ports = 2; | |||
| int wait_time = 0; | |||
| const JSList * node; | |||
| const jack_driver_param_t * param; | |||
| bool monitor = false; | |||
| for (node = params; node; node = jack_slist_next (node)) { | |||
| param = (const jack_driver_param_t *) node->data; | |||
| switch (param->character) { | |||
| case 'C': | |||
| capture_ports = param->value.ui; | |||
| break; | |||
| case 'P': | |||
| playback_ports = param->value.ui; | |||
| break; | |||
| case 'r': | |||
| sample_rate = param->value.ui; | |||
| break; | |||
| case 'p': | |||
| buffer_size = param->value.ui; | |||
| break; | |||
| case 'w': | |||
| wait_time = param->value.ui; | |||
| break; | |||
| case 'm': | |||
| monitor = param->value.i; | |||
| break; | |||
| } | |||
| } | |||
| if (wait_time > 0) { | |||
| buffer_size = lroundf((wait_time * sample_rate) / 1000000.0f); | |||
| if (buffer_size > BUFFER_SIZE_MAX) { | |||
| buffer_size = BUFFER_SIZE_MAX; | |||
| jack_error("Buffer size set to %d", BUFFER_SIZE_MAX); | |||
| } | |||
| } | |||
| Jack::JackDriverClientInterface* driver = new Jack::JackThreadedDriver(new Jack::JackGoldfishDriver("system", "goldfish_pcm", engine, table)); | |||
| if (driver->Open(buffer_size, sample_rate, 1, 1, capture_ports, playback_ports, monitor, "goldfish", "goldfish", 0, 0) == 0) { | |||
| return driver; | |||
| } else { | |||
| delete driver; | |||
| return NULL; | |||
| } | |||
| } | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| @@ -0,0 +1,70 @@ | |||
| /* | |||
| Copyright (C) 2001 Paul Davis | |||
| Copyright (C) 2004-2008 Grame | |||
| Copyright (C) 2013 Samsung Electronics | |||
| 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 program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| */ | |||
| #ifndef __JackGoldfishDriver__ | |||
| #define __JackGoldfishDriver__ | |||
| #include "JackAudioDriver.h" | |||
| namespace Jack | |||
| { | |||
| /*! | |||
| \brief The goldfish driver. | |||
| */ | |||
| class JackGoldfishDriver : public JackAudioDriver | |||
| { | |||
| public: | |||
| JackGoldfishDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) | |||
| : JackAudioDriver(name, alias, engine, table), mFd(-1), mBuffer(NULL) | |||
| {} | |||
| virtual ~JackGoldfishDriver() | |||
| {} | |||
| int Open(jack_nframes_t buffe_size, | |||
| jack_nframes_t samplerate, | |||
| bool capturing, | |||
| bool playing, | |||
| int chan_in, | |||
| int chan_out, | |||
| bool monitor, | |||
| const char* capture_driver_name, | |||
| const char* playback_driver_name, | |||
| jack_nframes_t capture_latency, | |||
| jack_nframes_t playback_latency); | |||
| int Close(); | |||
| int Read(); | |||
| int Write(); | |||
| int SetBufferSize(jack_nframes_t buffer_size); | |||
| private: | |||
| int mFd; | |||
| short *mBuffer; | |||
| }; | |||
| } // end of namespace | |||
| #endif | |||
| @@ -0,0 +1,236 @@ | |||
| /* | |||
| Copyright (C) 2001 Paul Davis | |||
| Copyright (C) 2004-2008 Grame | |||
| Copyright (C) 2013 Samsung Electronics | |||
| 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 program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| */ | |||
| #include "JackOpenSLESDriver.h" | |||
| #include "JackDriverLoader.h" | |||
| #include "JackThreadedDriver.h" | |||
| #include "JackEngineControl.h" | |||
| #include "JackGraphManager.h" | |||
| #include "JackCompilerDeps.h" | |||
| #include <iostream> | |||
| #include <unistd.h> | |||
| #include <fcntl.h> | |||
| #include <math.h> | |||
| #include <android/log.h> | |||
| #include "opensl_io.h" | |||
| #define JACK_OPENSLES_DEFAULT_SAMPLERATE 48000 | |||
| #define JACK_OPENSLES_DEFAULT_BUFFER_SIZE 1024 | |||
| namespace Jack | |||
| { | |||
| static OPENSL_STREAM *pOpenSL_stream; | |||
| int JackOpenSLESDriver::Open(jack_nframes_t buffer_size, | |||
| jack_nframes_t samplerate, | |||
| bool capturing, | |||
| bool playing, | |||
| int inchannels, | |||
| int outchannels, | |||
| bool monitor, | |||
| const char* capture_driver_uid, | |||
| const char* playback_driver_uid, | |||
| jack_nframes_t capture_latency, | |||
| jack_nframes_t playback_latency) { | |||
| jack_log("JackOpenSLESDriver::Open"); | |||
| // Generic JackAudioDriver Open | |||
| if (JackAudioDriver::Open(buffer_size, samplerate, capturing, playing, inchannels, outchannels, monitor, | |||
| capture_driver_uid, playback_driver_uid, capture_latency, playback_latency) != 0) { | |||
| return -1; | |||
| } | |||
| //JackAudioDriver::SetBufferSize(buffer_size); | |||
| //JackAudioDriver::SetSampleRate(samplerate); | |||
| if (capturing) { | |||
| inbuffer = (float *) malloc(sizeof(float) * buffer_size); //mono input | |||
| memset(inbuffer, 0, sizeof(float) * buffer_size); | |||
| } | |||
| if (playing) { | |||
| outbuffer = (float *) malloc(sizeof(float) * buffer_size * 2); //stereo output | |||
| memset(outbuffer, 0, sizeof(float) * buffer_size * 2); | |||
| } | |||
| pOpenSL_stream = android_OpenAudioDevice(samplerate, capturing ? 1 : 0, playing ? 2 : 0, buffer_size); | |||
| if (pOpenSL_stream == NULL) return -1; | |||
| return 0; | |||
| } | |||
| int JackOpenSLESDriver::Close() { | |||
| jack_log("JackOpenSLESDriver::Close"); | |||
| // Generic audio driver close | |||
| int res = JackAudioDriver::Close(); | |||
| android_CloseAudioDevice(pOpenSL_stream); | |||
| if (inbuffer) { | |||
| free(inbuffer); | |||
| inbuffer = NULL; | |||
| } | |||
| if (outbuffer) { | |||
| free(outbuffer); | |||
| outbuffer = NULL; | |||
| } | |||
| return res; | |||
| } | |||
| int JackOpenSLESDriver::Read() { | |||
| //jack_log("JackOpenSLESDriver::Read"); | |||
| jack_default_audio_sample_t* inputBuffer_1 = GetInputBuffer(0); | |||
| jack_default_audio_sample_t* inputBuffer_2 = GetInputBuffer(1); | |||
| if (inbuffer) { | |||
| int samps = android_AudioIn(pOpenSL_stream,inbuffer,fEngineControl->fBufferSize); | |||
| //jack_log("JackOpenSLESDriver::Read(%d)", samps); //for debug | |||
| for (int i = 0; i < samps; i++) { | |||
| *(inputBuffer_1 + i) = *(inbuffer + i); | |||
| *(inputBuffer_2 + i) = *(inbuffer + i); | |||
| } | |||
| } else { | |||
| for (int i = 0; i < fCaptureChannels; i++) { | |||
| memset(GetInputBuffer(i), 0, sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize); //silence | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| int JackOpenSLESDriver::Write() { | |||
| //jack_log("JackOpenSLESDriver::Write"); | |||
| jack_default_audio_sample_t* outputBuffer_1 = GetOutputBuffer(0); | |||
| jack_default_audio_sample_t* outputBuffer_2 = GetOutputBuffer(1); | |||
| if (outbuffer) { | |||
| android_AudioOut(pOpenSL_stream, outbuffer, fEngineControl->fBufferSize * 2); //stereo output | |||
| for (unsigned int i = 0, j = 0; i < fEngineControl->fBufferSize; i++) { | |||
| *(outbuffer + j) = *(outputBuffer_1 + i); j++; | |||
| *(outbuffer + j) = *(outputBuffer_2 + i); j++; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| int JackOpenSLESDriver::SetBufferSize(jack_nframes_t buffer_size) { | |||
| jack_log("JackOpenSLESDriver::SetBufferSize"); | |||
| JackAudioDriver::SetBufferSize(buffer_size); | |||
| return 0; | |||
| } | |||
| } // end of namespace | |||
| #ifdef __cplusplus | |||
| extern "C" | |||
| { | |||
| #endif | |||
| SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor () { | |||
| jack_driver_desc_t * desc; | |||
| jack_driver_desc_filler_t filler; | |||
| jack_driver_param_value_t value; | |||
| desc = jack_driver_descriptor_construct("opensles", JackDriverMaster, "Timer based backend", &filler); | |||
| value.ui = 2U; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamUInt, &value, NULL, "Number of capture ports", NULL); | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "playback", 'P', JackDriverParamUInt, &value, NULL, "Number of playback ports", NULL); | |||
| value.ui = 48000U; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL); | |||
| value.i = 0; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "monitor", 'm', JackDriverParamBool, &value, NULL, "Provide monitor ports for the output", NULL); | |||
| value.ui = JACK_OPENSLES_DEFAULT_BUFFER_SIZE; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames per period", NULL); | |||
| value.ui = 21333U; | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "wait", 'w', JackDriverParamUInt, &value, NULL, "Number of usecs to wait between engine processes", NULL); | |||
| return desc; | |||
| } | |||
| SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) { | |||
| jack_nframes_t sample_rate = JACK_OPENSLES_DEFAULT_SAMPLERATE; | |||
| jack_nframes_t buffer_size = JACK_OPENSLES_DEFAULT_BUFFER_SIZE; | |||
| unsigned int capture_ports = 2; | |||
| unsigned int playback_ports = 2; | |||
| int wait_time = 0; | |||
| const JSList * node; | |||
| const jack_driver_param_t * param; | |||
| bool monitor = false; | |||
| for (node = params; node; node = jack_slist_next (node)) { | |||
| param = (const jack_driver_param_t *) node->data; | |||
| switch (param->character) { | |||
| case 'C': | |||
| capture_ports = param->value.ui; | |||
| break; | |||
| case 'P': | |||
| playback_ports = param->value.ui; | |||
| break; | |||
| case 'r': | |||
| sample_rate = param->value.ui; | |||
| break; | |||
| case 'p': | |||
| buffer_size = param->value.ui; | |||
| break; | |||
| case 'w': | |||
| wait_time = param->value.ui; | |||
| break; | |||
| case 'm': | |||
| monitor = param->value.i; | |||
| break; | |||
| } | |||
| } | |||
| if (wait_time > 0) { | |||
| buffer_size = lroundf((wait_time * sample_rate) / 1000000.0f); | |||
| if (buffer_size > BUFFER_SIZE_MAX) { | |||
| buffer_size = BUFFER_SIZE_MAX; | |||
| jack_error("Buffer size set to %d", BUFFER_SIZE_MAX); | |||
| } | |||
| } | |||
| Jack::JackDriverClientInterface* driver = new Jack::JackThreadedDriver(new Jack::JackOpenSLESDriver("system", "opensles_pcm", engine, table)); | |||
| if (driver->Open(buffer_size, sample_rate, capture_ports? 1 : 0, playback_ports? 1 : 0, capture_ports, playback_ports, monitor, "opensles", "opensles", 0, 0) == 0) { | |||
| return driver; | |||
| } else { | |||
| delete driver; | |||
| return NULL; | |||
| } | |||
| } | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| @@ -0,0 +1,70 @@ | |||
| /* | |||
| Copyright (C) 2001 Paul Davis | |||
| Copyright (C) 2004-2008 Grame | |||
| Copyright (C) 2013 Samsung Electronics | |||
| 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 program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| */ | |||
| #ifndef __JackOpenSLESDriver__ | |||
| #define __JackOpenSLESDriver__ | |||
| #include "JackAudioDriver.h" | |||
| namespace Jack | |||
| { | |||
| /*! | |||
| \brief The OpenSLES driver. | |||
| */ | |||
| class JackOpenSLESDriver : public JackAudioDriver | |||
| { | |||
| public: | |||
| JackOpenSLESDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) | |||
| : JackAudioDriver(name, alias, engine, table), inbuffer(NULL), outbuffer(NULL) | |||
| {} | |||
| virtual ~JackOpenSLESDriver() | |||
| {} | |||
| int Open(jack_nframes_t buffe_size, | |||
| jack_nframes_t samplerate, | |||
| bool capturing, | |||
| bool playing, | |||
| int chan_in, | |||
| int chan_out, | |||
| bool monitor, | |||
| const char* capture_driver_name, | |||
| const char* playback_driver_name, | |||
| jack_nframes_t capture_latency, | |||
| jack_nframes_t playback_latency); | |||
| int Close(); | |||
| int Read(); | |||
| int Write(); | |||
| int SetBufferSize(jack_nframes_t buffer_size); | |||
| private: | |||
| float *inbuffer; | |||
| float *outbuffer; | |||
| }; | |||
| } // end of namespace | |||
| #endif | |||
| @@ -0,0 +1,91 @@ | |||
| /* | |||
| Copyright (C) 2004-2008 Grame | |||
| Copyright (C) 2013 Samsung Electronics | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU Lesser General Public License as published by | |||
| the Free Software Foundation; either version 2.1 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| #ifndef __JackPlatformPlug_android__ | |||
| #define __JackPlatformPlug_android__ | |||
| #define jack_server_dir "/data/misc/jack" | |||
| #define jack_client_dir "/data/misc/jack" | |||
| #define JACK_DEFAULT_DRIVER "alsa" | |||
| namespace Jack | |||
| { | |||
| struct JackRequest; | |||
| struct JackResult; | |||
| class JackPosixMutex; | |||
| class JackAndroidThread; | |||
| class JackFifo; | |||
| class JackSocketServerChannel; | |||
| class JackSocketClientChannel; | |||
| class JackSocketServerNotifyChannel; | |||
| class JackSocketNotifyChannel; | |||
| class JackClientSocket; | |||
| class JackNetUnixSocket; | |||
| } | |||
| /* __JackPlatformMutex__ */ | |||
| #include "JackPosixMutex.h" | |||
| namespace Jack {typedef JackPosixMutex JackMutex; } | |||
| /* __JackPlatformThread__ */ | |||
| #include "JackAndroidThread.h" | |||
| namespace Jack { typedef JackAndroidThread JackThread; } | |||
| /* __JackPlatformSynchro__ client activation */ | |||
| /* | |||
| #include "JackFifo.h" | |||
| namespace Jack { typedef JackFifo JackSynchro; } | |||
| */ | |||
| #include "JackAndroidSemaphore.h" | |||
| namespace Jack { typedef JackAndroidSemaphore JackSynchro; } | |||
| /* __JackPlatformChannelTransaction__ */ | |||
| /* | |||
| #include "JackSocket.h" | |||
| namespace Jack { typedef JackClientSocket JackChannelTransaction; } | |||
| */ | |||
| /* __JackPlatformProcessSync__ */ | |||
| #include "JackPosixProcessSync.h" | |||
| namespace Jack { typedef JackPosixProcessSync JackProcessSync; } | |||
| /* __JackPlatformServerChannel__ */ | |||
| #include "JackSocketServerChannel.h" | |||
| namespace Jack { typedef JackSocketServerChannel JackServerChannel; } | |||
| /* __JackPlatformClientChannel__ */ | |||
| #include "JackSocketClientChannel.h" | |||
| namespace Jack { typedef JackSocketClientChannel JackClientChannel; } | |||
| /* __JackPlatformServerNotifyChannel__ */ | |||
| #include "JackSocketServerNotifyChannel.h" | |||
| namespace Jack { typedef JackSocketServerNotifyChannel JackServerNotifyChannel; } | |||
| /* __JackPlatformNotifyChannel__ */ | |||
| #include "JackSocketNotifyChannel.h" | |||
| namespace Jack { typedef JackSocketNotifyChannel JackNotifyChannel; } | |||
| /* __JackPlatformNetSocket__ */ | |||
| #include "JackNetUnixSocket.h" | |||
| namespace Jack { typedef JackNetUnixSocket JackNetSocket; } | |||
| #endif | |||
| @@ -0,0 +1,40 @@ | |||
| /* | |||
| Copyright (C) 2004-2008 Grame | |||
| Copyright (C) 2013 Samsung Electronics | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU Lesser General Public License as published by | |||
| the Free Software Foundation; either version 2.1 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| #ifndef __JackShmMem__android__ | |||
| #define __JackShmMem__android__ | |||
| #include <sys/types.h> | |||
| #include <sys/mman.h> | |||
| #define CHECK_MLOCK(ptr, size) (mlock((ptr), (size)) == 0) | |||
| #define CHECK_MUNLOCK(ptr, size) (munlock((ptr), (size)) == 0) | |||
| #define CHECK_MLOCKALL() (false) | |||
| #define CHECK_MUNLOCKALL() (false) | |||
| /* fix for crash jack server issue: | |||
| * case 1) jack_destroy_shm() in JackShmReadWritePtr1::Init() causes crash | |||
| * because server lost shared memory by destroying client side ahead. | |||
| */ | |||
| #ifndef SERVER_SIDE | |||
| #define jack_destroy_shm(x) (0) | |||
| #endif | |||
| #endif /* __JackShmMem__android__ */ | |||
| @@ -0,0 +1,32 @@ | |||
| /* | |||
| Copyright (C) 2004-2008 Grame | |||
| Copyright (C) 2013 Samsung Electronics | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU Lesser General Public License as published by | |||
| the Free Software Foundation; either version 2.1 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| #ifndef __JackSystemDeps_android__ | |||
| #define __JackSystemDeps_android__ | |||
| #include "../posix/JackSystemDeps_os.h" | |||
| /** | |||
| * bionic c dependant functions | |||
| */ | |||
| #define pthread_setcanceltype(x,y) (0) | |||
| #endif /* __JackSystemDeps_android__ */ | |||
| @@ -0,0 +1,869 @@ | |||
| GNU GENERAL PUBLIC LICENSE | |||
| Version 2, June 1991 | |||
| Copyright (C) 1989, 1991 Free Software Foundation, Inc., | |||
| 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| Everyone is permitted to copy and distribute verbatim copies | |||
| of this license document, but changing it is not allowed. | |||
| Preamble | |||
| The licenses for most software are designed to take away your | |||
| freedom to share and change it. By contrast, the GNU General Public | |||
| License is intended to guarantee your freedom to share and change free | |||
| software--to make sure the software is free for all its users. This | |||
| General Public License applies to most of the Free Software | |||
| Foundation's software and to any other program whose authors commit to | |||
| using it. (Some other Free Software Foundation software is covered by | |||
| the GNU Lesser General Public License instead.) You can apply it to | |||
| your programs, too. | |||
| When we speak of free software, we are referring to freedom, not | |||
| price. Our General Public Licenses are designed to make sure that you | |||
| have the freedom to distribute copies of free software (and charge for | |||
| this service if you wish), that you receive source code or can get it | |||
| if you want it, that you can change the software or use pieces of it | |||
| in new free programs; and that you know you can do these things. | |||
| To protect your rights, we need to make restrictions that forbid | |||
| anyone to deny you these rights or to ask you to surrender the rights. | |||
| These restrictions translate to certain responsibilities for you if you | |||
| distribute copies of the software, or if you modify it. | |||
| For example, if you distribute copies of such a program, whether | |||
| gratis or for a fee, you must give the recipients all the rights that | |||
| you have. You must make sure that they, too, receive or can get the | |||
| source code. And you must show them these terms so they know their | |||
| rights. | |||
| We protect your rights with two steps: (1) copyright the software, and | |||
| (2) offer you this license which gives you legal permission to copy, | |||
| distribute and/or modify the software. | |||
| Also, for each author's protection and ours, we want to make certain | |||
| that everyone understands that there is no warranty for this free | |||
| software. If the software is modified by someone else and passed on, we | |||
| want its recipients to know that what they have is not the original, so | |||
| that any problems introduced by others will not reflect on the original | |||
| authors' reputations. | |||
| Finally, any free program is threatened constantly by software | |||
| patents. We wish to avoid the danger that redistributors of a free | |||
| program will individually obtain patent licenses, in effect making the | |||
| program proprietary. To prevent this, we have made it clear that any | |||
| patent must be licensed for everyone's free use or not licensed at all. | |||
| The precise terms and conditions for copying, distribution and | |||
| modification follow. | |||
| GNU GENERAL PUBLIC LICENSE | |||
| TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |||
| 0. This License applies to any program or other work which contains | |||
| a notice placed by the copyright holder saying it may be distributed | |||
| under the terms of this General Public License. The "Program", below, | |||
| refers to any such program or work, and a "work based on the Program" | |||
| means either the Program or any derivative work under copyright law: | |||
| that is to say, a work containing the Program or a portion of it, | |||
| either verbatim or with modifications and/or translated into another | |||
| language. (Hereinafter, translation is included without limitation in | |||
| the term "modification".) Each licensee is addressed as "you". | |||
| Activities other than copying, distribution and modification are not | |||
| covered by this License; they are outside its scope. The act of | |||
| running the Program is not restricted, and the output from the Program | |||
| is covered only if its contents constitute a work based on the | |||
| Program (independent of having been made by running the Program). | |||
| Whether that is true depends on what the Program does. | |||
| 1. You may copy and distribute verbatim copies of the Program's | |||
| source code as you receive it, in any medium, provided that you | |||
| conspicuously and appropriately publish on each copy an appropriate | |||
| copyright notice and disclaimer of warranty; keep intact all the | |||
| notices that refer to this License and to the absence of any warranty; | |||
| and give any other recipients of the Program a copy of this License | |||
| along with the Program. | |||
| You may charge a fee for the physical act of transferring a copy, and | |||
| you may at your option offer warranty protection in exchange for a fee. | |||
| 2. You may modify your copy or copies of the Program or any portion | |||
| of it, thus forming a work based on the Program, and copy and | |||
| distribute such modifications or work under the terms of Section 1 | |||
| above, provided that you also meet all of these conditions: | |||
| a) You must cause the modified files to carry prominent notices | |||
| stating that you changed the files and the date of any change. | |||
| b) You must cause any work that you distribute or publish, that in | |||
| whole or in part contains or is derived from the Program or any | |||
| part thereof, to be licensed as a whole at no charge to all third | |||
| parties under the terms of this License. | |||
| c) If the modified program normally reads commands interactively | |||
| when run, you must cause it, when started running for such | |||
| interactive use in the most ordinary way, to print or display an | |||
| announcement including an appropriate copyright notice and a | |||
| notice that there is no warranty (or else, saying that you provide | |||
| a warranty) and that users may redistribute the program under | |||
| these conditions, and telling the user how to view a copy of this | |||
| License. (Exception: if the Program itself is interactive but | |||
| does not normally print such an announcement, your work based on | |||
| the Program is not required to print an announcement.) | |||
| These requirements apply to the modified work as a whole. If | |||
| identifiable sections of that work are not derived from the Program, | |||
| and can be reasonably considered independent and separate works in | |||
| themselves, then this License, and its terms, do not apply to those | |||
| sections when you distribute them as separate works. But when you | |||
| distribute the same sections as part of a whole which is a work based | |||
| on the Program, the distribution of the whole must be on the terms of | |||
| this License, whose permissions for other licensees extend to the | |||
| entire whole, and thus to each and every part regardless of who wrote it. | |||
| Thus, it is not the intent of this section to claim rights or contest | |||
| your rights to work written entirely by you; rather, the intent is to | |||
| exercise the right to control the distribution of derivative or | |||
| collective works based on the Program. | |||
| In addition, mere aggregation of another work not based on the Program | |||
| with the Program (or with a work based on the Program) on a volume of | |||
| a storage or distribution medium does not bring the other work under | |||
| the scope of this License. | |||
| 3. You may copy and distribute the Program (or a work based on it, | |||
| under Section 2) in object code or executable form under the terms of | |||
| Sections 1 and 2 above provided that you also do one of the following: | |||
| a) Accompany it with the complete corresponding machine-readable | |||
| source code, which must be distributed under the terms of Sections | |||
| 1 and 2 above on a medium customarily used for software interchange; or, | |||
| b) Accompany it with a written offer, valid for at least three | |||
| years, to give any third party, for a charge no more than your | |||
| cost of physically performing source distribution, a complete | |||
| machine-readable copy of the corresponding source code, to be | |||
| distributed under the terms of Sections 1 and 2 above on a medium | |||
| customarily used for software interchange; or, | |||
| c) Accompany it with the information you received as to the offer | |||
| to distribute corresponding source code. (This alternative is | |||
| allowed only for noncommercial distribution and only if you | |||
| received the program in object code or executable form with such | |||
| an offer, in accord with Subsection b above.) | |||
| The source code for a work means the preferred form of the work for | |||
| making modifications to it. For an executable work, complete source | |||
| code means all the source code for all modules it contains, plus any | |||
| associated interface definition files, plus the scripts used to | |||
| control compilation and installation of the executable. However, as a | |||
| special exception, the source code distributed need not include | |||
| anything that is normally distributed (in either source or binary | |||
| form) with the major components (compiler, kernel, and so on) of the | |||
| operating system on which the executable runs, unless that component | |||
| itself accompanies the executable. | |||
| If distribution of executable or object code is made by offering | |||
| access to copy from a designated place, then offering equivalent | |||
| access to copy the source code from the same place counts as | |||
| distribution of the source code, even though third parties are not | |||
| compelled to copy the source along with the object code. | |||
| 4. You may not copy, modify, sublicense, or distribute the Program | |||
| except as expressly provided under this License. Any attempt | |||
| otherwise to copy, modify, sublicense or distribute the Program is | |||
| void, and will automatically terminate your rights under this License. | |||
| However, parties who have received copies, or rights, from you under | |||
| this License will not have their licenses terminated so long as such | |||
| parties remain in full compliance. | |||
| 5. You are not required to accept this License, since you have not | |||
| signed it. However, nothing else grants you permission to modify or | |||
| distribute the Program or its derivative works. These actions are | |||
| prohibited by law if you do not accept this License. Therefore, by | |||
| modifying or distributing the Program (or any work based on the | |||
| Program), you indicate your acceptance of this License to do so, and | |||
| all its terms and conditions for copying, distributing or modifying | |||
| the Program or works based on it. | |||
| 6. Each time you redistribute the Program (or any work based on the | |||
| Program), the recipient automatically receives a license from the | |||
| original licensor to copy, distribute or modify the Program subject to | |||
| these terms and conditions. You may not impose any further | |||
| restrictions on the recipients' exercise of the rights granted herein. | |||
| You are not responsible for enforcing compliance by third parties to | |||
| this License. | |||
| 7. If, as a consequence of a court judgment or allegation of patent | |||
| infringement or for any other reason (not limited to patent issues), | |||
| conditions are imposed on you (whether by court order, agreement or | |||
| otherwise) that contradict the conditions of this License, they do not | |||
| excuse you from the conditions of this License. If you cannot | |||
| distribute so as to satisfy simultaneously your obligations under this | |||
| License and any other pertinent obligations, then as a consequence you | |||
| may not distribute the Program at all. For example, if a patent | |||
| license would not permit royalty-free redistribution of the Program by | |||
| all those who receive copies directly or indirectly through you, then | |||
| the only way you could satisfy both it and this License would be to | |||
| refrain entirely from distribution of the Program. | |||
| If any portion of this section is held invalid or unenforceable under | |||
| any particular circumstance, the balance of the section is intended to | |||
| apply and the section as a whole is intended to apply in other | |||
| circumstances. | |||
| It is not the purpose of this section to induce you to infringe any | |||
| patents or other property right claims or to contest validity of any | |||
| such claims; this section has the sole purpose of protecting the | |||
| integrity of the free software distribution system, which is | |||
| implemented by public license practices. Many people have made | |||
| generous contributions to the wide range of software distributed | |||
| through that system in reliance on consistent application of that | |||
| system; it is up to the author/donor to decide if he or she is willing | |||
| to distribute software through any other system and a licensee cannot | |||
| impose that choice. | |||
| This section is intended to make thoroughly clear what is believed to | |||
| be a consequence of the rest of this License. | |||
| 8. If the distribution and/or use of the Program is restricted in | |||
| certain countries either by patents or by copyrighted interfaces, the | |||
| original copyright holder who places the Program under this License | |||
| may add an explicit geographical distribution limitation excluding | |||
| those countries, so that distribution is permitted only in or among | |||
| countries not thus excluded. In such case, this License incorporates | |||
| the limitation as if written in the body of this License. | |||
| 9. The Free Software Foundation may publish revised and/or new versions | |||
| of the General Public License from time to time. Such new versions will | |||
| be similar in spirit to the present version, but may differ in detail to | |||
| address new problems or concerns. | |||
| Each version is given a distinguishing version number. If the Program | |||
| specifies a version number of this License which applies to it and "any | |||
| later version", you have the option of following the terms and conditions | |||
| either of that version or of any later version published by the Free | |||
| Software Foundation. If the Program does not specify a version number of | |||
| this License, you may choose any version ever published by the Free Software | |||
| Foundation. | |||
| 10. If you wish to incorporate parts of the Program into other free | |||
| programs whose distribution conditions are different, write to the author | |||
| to ask for permission. For software which is copyrighted by the Free | |||
| Software Foundation, write to the Free Software Foundation; we sometimes | |||
| make exceptions for this. Our decision will be guided by the two goals | |||
| of preserving the free status of all derivatives of our free software and | |||
| of promoting the sharing and reuse of software generally. | |||
| NO WARRANTY | |||
| 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | |||
| FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN | |||
| OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | |||
| PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | |||
| OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |||
| MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS | |||
| TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE | |||
| PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | |||
| REPAIR OR CORRECTION. | |||
| 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |||
| WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | |||
| REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | |||
| INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | |||
| OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | |||
| TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | |||
| YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | |||
| PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | |||
| POSSIBILITY OF SUCH DAMAGES. | |||
| END OF TERMS AND CONDITIONS | |||
| How to Apply These Terms to Your New Programs | |||
| If you develop a new program, and you want it to be of the greatest | |||
| possible use to the public, the best way to achieve this is to make it | |||
| free software which everyone can redistribute and change under these terms. | |||
| To do so, attach the following notices to the program. It is safest | |||
| to attach them to the start of each source file to most effectively | |||
| convey the exclusion of warranty; and each file should have at least | |||
| the "copyright" line and a pointer to where the full notice is found. | |||
| <one line to give the program's name and a brief idea of what it does.> | |||
| Copyright (C) <year> <name of author> | |||
| 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 program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License along | |||
| with this program; if not, write to the Free Software Foundation, Inc., | |||
| 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| Also add information on how to contact you by electronic and paper mail. | |||
| If the program is interactive, make it output a short notice like this | |||
| when it starts in an interactive mode: | |||
| Gnomovision version 69, Copyright (C) year name of author | |||
| Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | |||
| This is free software, and you are welcome to redistribute it | |||
| under certain conditions; type `show c' for details. | |||
| The hypothetical commands `show w' and `show c' should show the appropriate | |||
| parts of the General Public License. Of course, the commands you use may | |||
| be called something other than `show w' and `show c'; they could even be | |||
| mouse-clicks or menu items--whatever suits your program. | |||
| You should also get your employer (if you work as a programmer) or your | |||
| school, if any, to sign a "copyright disclaimer" for the program, if | |||
| necessary. Here is a sample; alter the names: | |||
| Yoyodyne, Inc., hereby disclaims all copyright interest in the program | |||
| `Gnomovision' (which makes passes at compilers) written by James Hacker. | |||
| <signature of Ty Coon>, 1 April 1989 | |||
| Ty Coon, President of Vice | |||
| This General Public License does not permit incorporating your program into | |||
| proprietary programs. If your program is a subroutine library, you may | |||
| consider it more useful to permit linking proprietary applications with the | |||
| library. If this is what you want to do, use the GNU Lesser General | |||
| Public License instead of this License. | |||
| ------------------------------------------------------------------------------- | |||
| GNU LESSER GENERAL PUBLIC LICENSE | |||
| Version 2.1, February 1999 | |||
| Copyright (C) 1991, 1999 Free Software Foundation, Inc. | |||
| 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| Everyone is permitted to copy and distribute verbatim copies | |||
| of this license document, but changing it is not allowed. | |||
| [This is the first released version of the Lesser GPL. It also counts | |||
| as the successor of the GNU Library Public License, version 2, hence | |||
| the version number 2.1.] | |||
| Preamble | |||
| The licenses for most software are designed to take away your | |||
| freedom to share and change it. By contrast, the GNU General Public | |||
| Licenses are intended to guarantee your freedom to share and change | |||
| free software--to make sure the software is free for all its users. | |||
| This license, the Lesser General Public License, applies to some | |||
| specially designated software packages--typically libraries--of the | |||
| Free Software Foundation and other authors who decide to use it. You | |||
| can use it too, but we suggest you first think carefully about whether | |||
| this license or the ordinary General Public License is the better | |||
| strategy to use in any particular case, based on the explanations below. | |||
| When we speak of free software, we are referring to freedom of use, | |||
| not price. Our General Public Licenses are designed to make sure that | |||
| you have the freedom to distribute copies of free software (and charge | |||
| for this service if you wish); that you receive source code or can get | |||
| it if you want it; that you can change the software and use pieces of | |||
| it in new free programs; and that you are informed that you can do | |||
| these things. | |||
| To protect your rights, we need to make restrictions that forbid | |||
| distributors to deny you these rights or to ask you to surrender these | |||
| rights. These restrictions translate to certain responsibilities for | |||
| you if you distribute copies of the library or if you modify it. | |||
| For example, if you distribute copies of the library, whether gratis | |||
| or for a fee, you must give the recipients all the rights that we gave | |||
| you. You must make sure that they, too, receive or can get the source | |||
| code. If you link other code with the library, you must provide | |||
| complete object files to the recipients, so that they can relink them | |||
| with the library after making changes to the library and recompiling | |||
| it. And you must show them these terms so they know their rights. | |||
| We protect your rights with a two-step method: (1) we copyright the | |||
| library, and (2) we offer you this license, which gives you legal | |||
| permission to copy, distribute and/or modify the library. | |||
| To protect each distributor, we want to make it very clear that | |||
| there is no warranty for the free library. Also, if the library is | |||
| modified by someone else and passed on, the recipients should know | |||
| that what they have is not the original version, so that the original | |||
| author's reputation will not be affected by problems that might be | |||
| introduced by others. | |||
| Finally, software patents pose a constant threat to the existence of | |||
| any free program. We wish to make sure that a company cannot | |||
| effectively restrict the users of a free program by obtaining a | |||
| restrictive license from a patent holder. Therefore, we insist that | |||
| any patent license obtained for a version of the library must be | |||
| consistent with the full freedom of use specified in this license. | |||
| Most GNU software, including some libraries, is covered by the | |||
| ordinary GNU General Public License. This license, the GNU Lesser | |||
| General Public License, applies to certain designated libraries, and | |||
| is quite different from the ordinary General Public License. We use | |||
| this license for certain libraries in order to permit linking those | |||
| libraries into non-free programs. | |||
| When a program is linked with a library, whether statically or using | |||
| a shared library, the combination of the two is legally speaking a | |||
| combined work, a derivative of the original library. The ordinary | |||
| General Public License therefore permits such linking only if the | |||
| entire combination fits its criteria of freedom. The Lesser General | |||
| Public License permits more lax criteria for linking other code with | |||
| the library. | |||
| We call this license the "Lesser" General Public License because it | |||
| does Less to protect the user's freedom than the ordinary General | |||
| Public License. It also provides other free software developers Less | |||
| of an advantage over competing non-free programs. These disadvantages | |||
| are the reason we use the ordinary General Public License for many | |||
| libraries. However, the Lesser license provides advantages in certain | |||
| special circumstances. | |||
| For example, on rare occasions, there may be a special need to | |||
| encourage the widest possible use of a certain library, so that it becomes | |||
| a de-facto standard. To achieve this, non-free programs must be | |||
| allowed to use the library. A more frequent case is that a free | |||
| library does the same job as widely used non-free libraries. In this | |||
| case, there is little to gain by limiting the free library to free | |||
| software only, so we use the Lesser General Public License. | |||
| In other cases, permission to use a particular library in non-free | |||
| programs enables a greater number of people to use a large body of | |||
| free software. For example, permission to use the GNU C Library in | |||
| non-free programs enables many more people to use the whole GNU | |||
| operating system, as well as its variant, the GNU/Linux operating | |||
| system. | |||
| Although the Lesser General Public License is Less protective of the | |||
| users' freedom, it does ensure that the user of a program that is | |||
| linked with the Library has the freedom and the wherewithal to run | |||
| that program using a modified version of the Library. | |||
| The precise terms and conditions for copying, distribution and | |||
| modification follow. Pay close attention to the difference between a | |||
| "work based on the library" and a "work that uses the library". The | |||
| former contains code derived from the library, whereas the latter must | |||
| be combined with the library in order to run. | |||
| GNU LESSER GENERAL PUBLIC LICENSE | |||
| TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |||
| 0. This License Agreement applies to any software library or other | |||
| program which contains a notice placed by the copyright holder or | |||
| other authorized party saying it may be distributed under the terms of | |||
| this Lesser General Public License (also called "this License"). | |||
| Each licensee is addressed as "you". | |||
| A "library" means a collection of software functions and/or data | |||
| prepared so as to be conveniently linked with application programs | |||
| (which use some of those functions and data) to form executables. | |||
| The "Library", below, refers to any such software library or work | |||
| which has been distributed under these terms. A "work based on the | |||
| Library" means either the Library or any derivative work under | |||
| copyright law: that is to say, a work containing the Library or a | |||
| portion of it, either verbatim or with modifications and/or translated | |||
| straightforwardly into another language. (Hereinafter, translation is | |||
| included without limitation in the term "modification".) | |||
| "Source code" for a work means the preferred form of the work for | |||
| making modifications to it. For a library, complete source code means | |||
| all the source code for all modules it contains, plus any associated | |||
| interface definition files, plus the scripts used to control compilation | |||
| and installation of the library. | |||
| Activities other than copying, distribution and modification are not | |||
| covered by this License; they are outside its scope. The act of | |||
| running a program using the Library is not restricted, and output from | |||
| such a program is covered only if its contents constitute a work based | |||
| on the Library (independent of the use of the Library in a tool for | |||
| writing it). Whether that is true depends on what the Library does | |||
| and what the program that uses the Library does. | |||
| 1. You may copy and distribute verbatim copies of the Library's | |||
| complete source code as you receive it, in any medium, provided that | |||
| you conspicuously and appropriately publish on each copy an | |||
| appropriate copyright notice and disclaimer of warranty; keep intact | |||
| all the notices that refer to this License and to the absence of any | |||
| warranty; and distribute a copy of this License along with the | |||
| Library. | |||
| You may charge a fee for the physical act of transferring a copy, | |||
| and you may at your option offer warranty protection in exchange for a | |||
| fee. | |||
| 2. You may modify your copy or copies of the Library or any portion | |||
| of it, thus forming a work based on the Library, and copy and | |||
| distribute such modifications or work under the terms of Section 1 | |||
| above, provided that you also meet all of these conditions: | |||
| a) The modified work must itself be a software library. | |||
| b) You must cause the files modified to carry prominent notices | |||
| stating that you changed the files and the date of any change. | |||
| c) You must cause the whole of the work to be licensed at no | |||
| charge to all third parties under the terms of this License. | |||
| d) If a facility in the modified Library refers to a function or a | |||
| table of data to be supplied by an application program that uses | |||
| the facility, other than as an argument passed when the facility | |||
| is invoked, then you must make a good faith effort to ensure that, | |||
| in the event an application does not supply such function or | |||
| table, the facility still operates, and performs whatever part of | |||
| its purpose remains meaningful. | |||
| (For example, a function in a library to compute square roots has | |||
| a purpose that is entirely well-defined independent of the | |||
| application. Therefore, Subsection 2d requires that any | |||
| application-supplied function or table used by this function must | |||
| be optional: if the application does not supply it, the square | |||
| root function must still compute square roots.) | |||
| These requirements apply to the modified work as a whole. If | |||
| identifiable sections of that work are not derived from the Library, | |||
| and can be reasonably considered independent and separate works in | |||
| themselves, then this License, and its terms, do not apply to those | |||
| sections when you distribute them as separate works. But when you | |||
| distribute the same sections as part of a whole which is a work based | |||
| on the Library, the distribution of the whole must be on the terms of | |||
| this License, whose permissions for other licensees extend to the | |||
| entire whole, and thus to each and every part regardless of who wrote | |||
| it. | |||
| Thus, it is not the intent of this section to claim rights or contest | |||
| your rights to work written entirely by you; rather, the intent is to | |||
| exercise the right to control the distribution of derivative or | |||
| collective works based on the Library. | |||
| In addition, mere aggregation of another work not based on the Library | |||
| with the Library (or with a work based on the Library) on a volume of | |||
| a storage or distribution medium does not bring the other work under | |||
| the scope of this License. | |||
| 3. You may opt to apply the terms of the ordinary GNU General Public | |||
| License instead of this License to a given copy of the Library. To do | |||
| this, you must alter all the notices that refer to this License, so | |||
| that they refer to the ordinary GNU General Public License, version 2, | |||
| instead of to this License. (If a newer version than version 2 of the | |||
| ordinary GNU General Public License has appeared, then you can specify | |||
| that version instead if you wish.) Do not make any other change in | |||
| these notices. | |||
| Once this change is made in a given copy, it is irreversible for | |||
| that copy, so the ordinary GNU General Public License applies to all | |||
| subsequent copies and derivative works made from that copy. | |||
| This option is useful when you wish to copy part of the code of | |||
| the Library into a program that is not a library. | |||
| 4. You may copy and distribute the Library (or a portion or | |||
| derivative of it, under Section 2) in object code or executable form | |||
| under the terms of Sections 1 and 2 above provided that you accompany | |||
| it with the complete corresponding machine-readable source code, which | |||
| must be distributed under the terms of Sections 1 and 2 above on a | |||
| medium customarily used for software interchange. | |||
| If distribution of object code is made by offering access to copy | |||
| from a designated place, then offering equivalent access to copy the | |||
| source code from the same place satisfies the requirement to | |||
| distribute the source code, even though third parties are not | |||
| compelled to copy the source along with the object code. | |||
| 5. A program that contains no derivative of any portion of the | |||
| Library, but is designed to work with the Library by being compiled or | |||
| linked with it, is called a "work that uses the Library". Such a | |||
| work, in isolation, is not a derivative work of the Library, and | |||
| therefore falls outside the scope of this License. | |||
| However, linking a "work that uses the Library" with the Library | |||
| creates an executable that is a derivative of the Library (because it | |||
| contains portions of the Library), rather than a "work that uses the | |||
| library". The executable is therefore covered by this License. | |||
| Section 6 states terms for distribution of such executables. | |||
| When a "work that uses the Library" uses material from a header file | |||
| that is part of the Library, the object code for the work may be a | |||
| derivative work of the Library even though the source code is not. | |||
| Whether this is true is especially significant if the work can be | |||
| linked without the Library, or if the work is itself a library. The | |||
| threshold for this to be true is not precisely defined by law. | |||
| If such an object file uses only numerical parameters, data | |||
| structure layouts and accessors, and small macros and small inline | |||
| functions (ten lines or less in length), then the use of the object | |||
| file is unrestricted, regardless of whether it is legally a derivative | |||
| work. (Executables containing this object code plus portions of the | |||
| Library will still fall under Section 6.) | |||
| Otherwise, if the work is a derivative of the Library, you may | |||
| distribute the object code for the work under the terms of Section 6. | |||
| Any executables containing that work also fall under Section 6, | |||
| whether or not they are linked directly with the Library itself. | |||
| 6. As an exception to the Sections above, you may also combine or | |||
| link a "work that uses the Library" with the Library to produce a | |||
| work containing portions of the Library, and distribute that work | |||
| under terms of your choice, provided that the terms permit | |||
| modification of the work for the customer's own use and reverse | |||
| engineering for debugging such modifications. | |||
| You must give prominent notice with each copy of the work that the | |||
| Library is used in it and that the Library and its use are covered by | |||
| this License. You must supply a copy of this License. If the work | |||
| during execution displays copyright notices, you must include the | |||
| copyright notice for the Library among them, as well as a reference | |||
| directing the user to the copy of this License. Also, you must do one | |||
| of these things: | |||
| a) Accompany the work with the complete corresponding | |||
| machine-readable source code for the Library including whatever | |||
| changes were used in the work (which must be distributed under | |||
| Sections 1 and 2 above); and, if the work is an executable linked | |||
| with the Library, with the complete machine-readable "work that | |||
| uses the Library", as object code and/or source code, so that the | |||
| user can modify the Library and then relink to produce a modified | |||
| executable containing the modified Library. (It is understood | |||
| that the user who changes the contents of definitions files in the | |||
| Library will not necessarily be able to recompile the application | |||
| to use the modified definitions.) | |||
| b) Use a suitable shared library mechanism for linking with the | |||
| Library. A suitable mechanism is one that (1) uses at run time a | |||
| copy of the library already present on the user's computer system, | |||
| rather than copying library functions into the executable, and (2) | |||
| will operate properly with a modified version of the library, if | |||
| the user installs one, as long as the modified version is | |||
| interface-compatible with the version that the work was made with. | |||
| c) Accompany the work with a written offer, valid for at | |||
| least three years, to give the same user the materials | |||
| specified in Subsection 6a, above, for a charge no more | |||
| than the cost of performing this distribution. | |||
| d) If distribution of the work is made by offering access to copy | |||
| from a designated place, offer equivalent access to copy the above | |||
| specified materials from the same place. | |||
| e) Verify that the user has already received a copy of these | |||
| materials or that you have already sent this user a copy. | |||
| For an executable, the required form of the "work that uses the | |||
| Library" must include any data and utility programs needed for | |||
| reproducing the executable from it. However, as a special exception, | |||
| the materials to be distributed need not include anything that is | |||
| normally distributed (in either source or binary form) with the major | |||
| components (compiler, kernel, and so on) of the operating system on | |||
| which the executable runs, unless that component itself accompanies | |||
| the executable. | |||
| It may happen that this requirement contradicts the license | |||
| restrictions of other proprietary libraries that do not normally | |||
| accompany the operating system. Such a contradiction means you cannot | |||
| use both them and the Library together in an executable that you | |||
| distribute. | |||
| 7. You may place library facilities that are a work based on the | |||
| Library side-by-side in a single library together with other library | |||
| facilities not covered by this License, and distribute such a combined | |||
| library, provided that the separate distribution of the work based on | |||
| the Library and of the other library facilities is otherwise | |||
| permitted, and provided that you do these two things: | |||
| a) Accompany the combined library with a copy of the same work | |||
| based on the Library, uncombined with any other library | |||
| facilities. This must be distributed under the terms of the | |||
| Sections above. | |||
| b) Give prominent notice with the combined library of the fact | |||
| that part of it is a work based on the Library, and explaining | |||
| where to find the accompanying uncombined form of the same work. | |||
| 8. You may not copy, modify, sublicense, link with, or distribute | |||
| the Library except as expressly provided under this License. Any | |||
| attempt otherwise to copy, modify, sublicense, link with, or | |||
| distribute the Library is void, and will automatically terminate your | |||
| rights under this License. However, parties who have received copies, | |||
| or rights, from you under this License will not have their licenses | |||
| terminated so long as such parties remain in full compliance. | |||
| 9. You are not required to accept this License, since you have not | |||
| signed it. However, nothing else grants you permission to modify or | |||
| distribute the Library or its derivative works. These actions are | |||
| prohibited by law if you do not accept this License. Therefore, by | |||
| modifying or distributing the Library (or any work based on the | |||
| Library), you indicate your acceptance of this License to do so, and | |||
| all its terms and conditions for copying, distributing or modifying | |||
| the Library or works based on it. | |||
| 10. Each time you redistribute the Library (or any work based on the | |||
| Library), the recipient automatically receives a license from the | |||
| original licensor to copy, distribute, link with or modify the Library | |||
| subject to these terms and conditions. You may not impose any further | |||
| restrictions on the recipients' exercise of the rights granted herein. | |||
| You are not responsible for enforcing compliance by third parties with | |||
| this License. | |||
| 11. If, as a consequence of a court judgment or allegation of patent | |||
| infringement or for any other reason (not limited to patent issues), | |||
| conditions are imposed on you (whether by court order, agreement or | |||
| otherwise) that contradict the conditions of this License, they do not | |||
| excuse you from the conditions of this License. If you cannot | |||
| distribute so as to satisfy simultaneously your obligations under this | |||
| License and any other pertinent obligations, then as a consequence you | |||
| may not distribute the Library at all. For example, if a patent | |||
| license would not permit royalty-free redistribution of the Library by | |||
| all those who receive copies directly or indirectly through you, then | |||
| the only way you could satisfy both it and this License would be to | |||
| refrain entirely from distribution of the Library. | |||
| If any portion of this section is held invalid or unenforceable under any | |||
| particular circumstance, the balance of the section is intended to apply, | |||
| and the section as a whole is intended to apply in other circumstances. | |||
| It is not the purpose of this section to induce you to infringe any | |||
| patents or other property right claims or to contest validity of any | |||
| such claims; this section has the sole purpose of protecting the | |||
| integrity of the free software distribution system which is | |||
| implemented by public license practices. Many people have made | |||
| generous contributions to the wide range of software distributed | |||
| through that system in reliance on consistent application of that | |||
| system; it is up to the author/donor to decide if he or she is willing | |||
| to distribute software through any other system and a licensee cannot | |||
| impose that choice. | |||
| This section is intended to make thoroughly clear what is believed to | |||
| be a consequence of the rest of this License. | |||
| 12. If the distribution and/or use of the Library is restricted in | |||
| certain countries either by patents or by copyrighted interfaces, the | |||
| original copyright holder who places the Library under this License may add | |||
| an explicit geographical distribution limitation excluding those countries, | |||
| so that distribution is permitted only in or among countries not thus | |||
| excluded. In such case, this License incorporates the limitation as if | |||
| written in the body of this License. | |||
| 13. The Free Software Foundation may publish revised and/or new | |||
| versions of the Lesser General Public License from time to time. | |||
| Such new versions will be similar in spirit to the present version, | |||
| but may differ in detail to address new problems or concerns. | |||
| Each version is given a distinguishing version number. If the Library | |||
| specifies a version number of this License which applies to it and | |||
| "any later version", you have the option of following the terms and | |||
| conditions either of that version or of any later version published by | |||
| the Free Software Foundation. If the Library does not specify a | |||
| license version number, you may choose any version ever published by | |||
| the Free Software Foundation. | |||
| 14. If you wish to incorporate parts of the Library into other free | |||
| programs whose distribution conditions are incompatible with these, | |||
| write to the author to ask for permission. For software which is | |||
| copyrighted by the Free Software Foundation, write to the Free | |||
| Software Foundation; we sometimes make exceptions for this. Our | |||
| decision will be guided by the two goals of preserving the free status | |||
| of all derivatives of our free software and of promoting the sharing | |||
| and reuse of software generally. | |||
| NO WARRANTY | |||
| 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO | |||
| WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. | |||
| EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR | |||
| OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY | |||
| KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE | |||
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||
| PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE | |||
| LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME | |||
| THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | |||
| 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN | |||
| WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY | |||
| AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU | |||
| FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR | |||
| CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE | |||
| LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING | |||
| RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A | |||
| FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF | |||
| SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | |||
| DAMAGES. | |||
| END OF TERMS AND CONDITIONS | |||
| How to Apply These Terms to Your New Libraries | |||
| If you develop a new library, and you want it to be of the greatest | |||
| possible use to the public, we recommend making it free software that | |||
| everyone can redistribute and change. You can do so by permitting | |||
| redistribution under these terms (or, alternatively, under the terms of the | |||
| ordinary General Public License). | |||
| To apply these terms, attach the following notices to the library. It is | |||
| safest to attach them to the start of each source file to most effectively | |||
| convey the exclusion of warranty; and each file should have at least the | |||
| "copyright" line and a pointer to where the full notice is found. | |||
| <one line to give the library's name and a brief idea of what it does.> | |||
| Copyright (C) <year> <name of author> | |||
| This library is free software; you can redistribute it and/or | |||
| modify it under the terms of the GNU Lesser General Public | |||
| License as published by the Free Software Foundation; either | |||
| version 2.1 of the License, or (at your option) any later version. | |||
| This library is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public | |||
| License along with this library; if not, write to the Free Software | |||
| Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| Also add information on how to contact you by electronic and paper mail. | |||
| You should also get your employer (if you work as a programmer) or your | |||
| school, if any, to sign a "copyright disclaimer" for the library, if | |||
| necessary. Here is a sample; alter the names: | |||
| Yoyodyne, Inc., hereby disclaims all copyright interest in the | |||
| library `Frob' (a library for tweaking knobs) written by James Random Hacker. | |||
| <signature of Ty Coon>, 1 April 1990 | |||
| Ty Coon, President of Vice | |||
| That's all there is to it! | |||
| ------------------------------------------------------------------------------- | |||
| opensl_io.c: | |||
| Android OpenSL input/output module (header) | |||
| Copyright (c) 2012, Victor Lazzarini | |||
| All rights reserved. | |||
| Redistribution and use in source and binary forms, with or without | |||
| modification, are permitted provided that the following conditions are met: | |||
| * Redistributions of source code must retain the above copyright | |||
| notice, this list of conditions and the following disclaimer. | |||
| * Redistributions in binary form must reproduce the above copyright | |||
| notice, this list of conditions and the following disclaimer in the | |||
| documentation and/or other materials provided with the distribution. | |||
| * Neither the name of the <organization> nor the | |||
| names of its contributors may be used to endorse or promote products | |||
| derived from this software without specific prior written permission. | |||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY | |||
| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| @@ -0,0 +1,886 @@ | |||
| /* | |||
| Copyright (C) 2001-2003 Paul Davis | |||
| Copyright (C) 2005-2012 Grame | |||
| Copyright (C) 2013 Samsung Electronics | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU Lesser General Public License as published by | |||
| the Free Software Foundation; either version 2.1 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| #define LOG_TAG "JAMSHMSERVICE" | |||
| #include <stddef.h> | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <unistd.h> | |||
| #include <binder/MemoryHeapBase.h> | |||
| #include <binder/IServiceManager.h> | |||
| #include <binder/IPCThreadState.h> | |||
| #include <utils/Log.h> | |||
| #include <sys/stat.h> | |||
| #include <sys/socket.h> | |||
| #include <sys/types.h> | |||
| #include <sys/un.h> | |||
| #include <sys/wait.h> | |||
| #include "BnAndroidShm.h" | |||
| #include "AndroidShm.h" | |||
| #include "JackConstants.h" | |||
| #include <fcntl.h> | |||
| #include <signal.h> | |||
| #include <limits.h> | |||
| #include <errno.h> | |||
| #include <dirent.h> | |||
| #include <sys/mman.h> | |||
| #include <linux/ashmem.h> | |||
| #include <cutils/ashmem.h> | |||
| #include "JackError.h" | |||
| // remove ALOGI log | |||
| #define jack_d | |||
| //#define jack_d ALOGI | |||
| #define jack_error ALOGE | |||
| #define MEMORY_SIZE 10*1024 | |||
| namespace android { | |||
| jack_shmtype_t Shm::jack_shmtype = shm_ANDROID; | |||
| /* The JACK SHM registry is a chunk of memory for keeping track of the | |||
| * shared memory used by each active JACK server. This allows the | |||
| * server to clean up shared memory when it exits. To avoid memory | |||
| * leakage due to kill -9, crashes or debugger-driven exits, this | |||
| * cleanup is also done when a new instance of that server starts. | |||
| */ | |||
| /* per-process global data for the SHM interfaces */ | |||
| jack_shm_id_t Shm::registry_id; /* SHM id for the registry */ | |||
| jack_shm_fd_t Shm::registry_fd = JACK_SHM_REGISTRY_FD; | |||
| jack_shm_info_t Shm::registry_info = { | |||
| JACK_SHM_NULL_INDEX, 0, 0, { MAP_FAILED } | |||
| }; | |||
| /* pointers to registry header and array */ | |||
| jack_shm_header_t *Shm::jack_shm_header = NULL; | |||
| jack_shm_registry_t *Shm::jack_shm_registry = NULL; | |||
| char Shm::jack_shm_server_prefix[JACK_SERVER_NAME_SIZE] = ""; | |||
| /* jack_shm_lock_registry() serializes updates to the shared memory | |||
| * segment JACK uses to keep track of the SHM segments allocated to | |||
| * all its processes, including multiple servers. | |||
| * | |||
| * This is not a high-contention lock, but it does need to work across | |||
| * multiple processes. High transaction rates and realtime safety are | |||
| * not required. Any solution needs to at least be portable to POSIX | |||
| * and POSIX-like systems. | |||
| * | |||
| * We must be particularly careful to ensure that the lock be released | |||
| * if the owning process terminates abnormally. Otherwise, a segfault | |||
| * or kill -9 at the wrong moment could prevent JACK from ever running | |||
| * again on that machine until after a reboot. | |||
| */ | |||
| #define JACK_SEMAPHORE_KEY 0x282929 | |||
| #define JACK_SHM_REGISTRY_KEY JACK_SEMAPHORE_KEY | |||
| #define JACK_REGISTRY_NAME "/jack-shm-registry" | |||
| int Shm::semid = -1; | |||
| pthread_mutex_t Shm::mutex = PTHREAD_MUTEX_INITIALIZER; | |||
| //sp<IAndroidShm> Shm::mShmService; | |||
| sp<IMemoryHeap> Shm::mShmMemBase[JACK_SHM_HEAP_ENOUGH_COUNT] = {0,}; | |||
| Shm* Shm::ref = NULL; | |||
| Shm* Shm::Instantiate() { | |||
| if(Shm::ref == NULL) { | |||
| jack_d("shm::Instantiate is called"); | |||
| Shm::ref = new Shm; | |||
| //AndroidShm::instantiate(); | |||
| } | |||
| return ref; | |||
| } | |||
| Shm::Shm() { } | |||
| Shm::~Shm() { } | |||
| sp<IAndroidShm> Shm::getShmService(){ | |||
| return interface_cast<IAndroidShm>(defaultServiceManager()->getService(String16("com.samsung.android.jam.IAndroidShm"))); | |||
| } | |||
| //sp<IAndroidShm>& Shm::getShmService() { | |||
| // if (mShmService.get() == 0) { | |||
| // sp<IServiceManager> sm = defaultServiceManager(); | |||
| // sp<IBinder> binder; | |||
| // do { | |||
| // binder = sm->getService(String16("com.samsung.android.jam.IAndroidShm")); | |||
| // if (binder != 0) | |||
| // break; | |||
| // ALOGW("CameraService not published, waiting..."); | |||
| // usleep(500000); // 0.5 s | |||
| // } while(true); | |||
| // mShmService = interface_cast<IAndroidShm>(binder); | |||
| // } | |||
| // ALOGE_IF(mShmService==0, "no CameraService!?"); | |||
| // return mShmService; | |||
| //} | |||
| void Shm::shm_copy_from_registry (jack_shm_info_t* /*si*/, jack_shm_registry_index_t ) { | |||
| // not used | |||
| } | |||
| void Shm::shm_copy_to_registry (jack_shm_info_t* /*si*/, jack_shm_registry_index_t*) { | |||
| // not used | |||
| } | |||
| void Shm::jack_release_shm_entry (jack_shm_registry_index_t index) { | |||
| /* the registry must be locked */ | |||
| jack_shm_registry[index].size = 0; | |||
| jack_shm_registry[index].allocator = 0; | |||
| memset (&jack_shm_registry[index].id, 0, | |||
| sizeof (jack_shm_registry[index].id)); | |||
| jack_shm_registry[index].fd = 0; | |||
| } | |||
| int Shm::release_shm_info (jack_shm_registry_index_t index) { | |||
| /* must NOT have the registry locked */ | |||
| if (jack_shm_registry[index].allocator == GetPID()) { | |||
| if (jack_shm_lock_registry () < 0) { | |||
| jack_error ("jack_shm_lock_registry fails..."); | |||
| return -1; | |||
| } | |||
| jack_release_shm_entry (index); | |||
| jack_shm_unlock_registry (); | |||
| jack_d ("release_shm_info: success!"); | |||
| } | |||
| else | |||
| jack_error ("release_shm_info: error!"); | |||
| return 0; | |||
| } | |||
| char* Shm::shm_addr (unsigned int fd) { | |||
| if(fd >= JACK_SHM_HEAP_ENOUGH_COUNT) { | |||
| jack_error("ignore to get memory buffer : index[%d] is too big", fd); | |||
| return NULL; | |||
| } | |||
| sp<IAndroidShm> service = Shm::getShmService(); | |||
| if(service == NULL){ | |||
| jack_error("shm service is null"); | |||
| return NULL; | |||
| } | |||
| mShmMemBase[fd] = service->getBuffer(fd); | |||
| if(mShmMemBase[fd] == NULL) { | |||
| jack_error("fail to get memory buffer"); | |||
| return NULL; | |||
| } | |||
| return ((char *) mShmMemBase[fd]->getBase()); | |||
| } | |||
| int Shm::shm_lock_registry (void) { | |||
| pthread_mutex_lock (&mutex); | |||
| return 0; | |||
| } | |||
| void Shm::shm_unlock_registry (void) { | |||
| pthread_mutex_unlock (&mutex); | |||
| } | |||
| void Shm::release_shm_entry (jack_shm_registry_index_t index) { | |||
| /* the registry must be locked */ | |||
| jack_shm_registry[index].size = 0; | |||
| jack_shm_registry[index].allocator = 0; | |||
| memset (&jack_shm_registry[index].id, 0, | |||
| sizeof (jack_shm_registry[index].id)); | |||
| } | |||
| void Shm::remove_shm (jack_shm_id_t *id) { | |||
| int shm_fd = -1; | |||
| jack_d("remove_id [%s]",(char*)id); | |||
| if(!strcmp((const char*)id, JACK_REGISTRY_NAME)) { | |||
| shm_fd = registry_fd; | |||
| } else { | |||
| for (int i = 0; i < MAX_SHM_ID; i++) { | |||
| if(!strcmp((const char*)id, jack_shm_registry[i].id)) { | |||
| shm_fd = jack_shm_registry[i].fd; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| if (shm_fd >= 0) { | |||
| sp<IAndroidShm> service = getShmService(); | |||
| if(service != NULL) { | |||
| service->removeShm(shm_fd); | |||
| } else { | |||
| jack_error("shm service is null"); | |||
| } | |||
| } | |||
| jack_d ("[APA] jack_remove_shm : ok "); | |||
| } | |||
| int Shm::access_registry (jack_shm_info_t * ri) { | |||
| jack_d("access_registry\n"); | |||
| /* registry must be locked */ | |||
| sp<IAndroidShm> service = getShmService(); | |||
| if(service == NULL){ | |||
| jack_error("shm service is null"); | |||
| return EINVAL; | |||
| } | |||
| int shm_fd = service->getRegistryIndex(); | |||
| strncpy (registry_id, JACK_REGISTRY_NAME, sizeof (registry_id) - 1); | |||
| registry_id[sizeof (registry_id) - 1] = '\0'; | |||
| if(service->isAllocated(shm_fd) == FALSE) { | |||
| //jack_error ("Cannot mmap shm registry segment (%s)", | |||
| // strerror (errno)); | |||
| jack_error ("Cannot mmap shm registry segment"); | |||
| //close (shm_fd); | |||
| ri->ptr.attached_at = NULL; | |||
| registry_fd = JACK_SHM_REGISTRY_FD; | |||
| return EINVAL; | |||
| } | |||
| ri->fd = shm_fd; | |||
| registry_fd = shm_fd; | |||
| ri->ptr.attached_at = shm_addr(shm_fd); | |||
| if(ri->ptr.attached_at == NULL) { | |||
| ALOGE("attached pointer is null !"); | |||
| jack_shm_header = NULL; | |||
| jack_shm_registry = NULL; | |||
| return 0; | |||
| } | |||
| /* set up global pointers */ | |||
| ri->index = JACK_SHM_REGISTRY_INDEX; | |||
| jack_shm_header = (jack_shm_header_t*)(ri->ptr.attached_at); | |||
| jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1); | |||
| jack_d("jack_shm_header[%p],jack_shm_registry[%p]", jack_shm_header, jack_shm_registry); | |||
| //close (shm_fd); // steph | |||
| return 0; | |||
| } | |||
| int Shm::GetUID() { | |||
| return getuid(); | |||
| } | |||
| int Shm::GetPID() { | |||
| return getpid(); | |||
| } | |||
| int Shm::jack_shm_lock_registry (void) { | |||
| // TODO: replace semaphore to mutex | |||
| pthread_mutex_lock (&mutex); | |||
| return 0; | |||
| } | |||
| void Shm::jack_shm_unlock_registry (void) { | |||
| // TODO: replace semaphore to mutex | |||
| pthread_mutex_unlock (&mutex); | |||
| return; | |||
| } | |||
| void Shm::shm_init_registry () { | |||
| if(jack_shm_header == NULL) | |||
| return; | |||
| /* registry must be locked */ | |||
| memset (jack_shm_header, 0, JACK_SHM_REGISTRY_SIZE); | |||
| jack_shm_header->magic = JACK_SHM_MAGIC; | |||
| //jack_shm_header->protocol = JACK_PROTOCOL_VERSION; | |||
| jack_shm_header->type = jack_shmtype; | |||
| jack_shm_header->size = JACK_SHM_REGISTRY_SIZE; | |||
| jack_shm_header->hdr_len = sizeof (jack_shm_header_t); | |||
| jack_shm_header->entry_len = sizeof (jack_shm_registry_t); | |||
| for (int i = 0; i < MAX_SHM_ID; ++i) { | |||
| jack_shm_registry[i].index = i; | |||
| } | |||
| } | |||
| void Shm::set_server_prefix (const char *server_name) { | |||
| snprintf (jack_shm_server_prefix, sizeof (jack_shm_server_prefix), | |||
| "jack-%d:%s:", GetUID(), server_name); | |||
| } | |||
| /* create a new SHM registry segment | |||
| * | |||
| * sets up global registry pointers, if successful | |||
| * | |||
| * returns: 0 if registry created successfully | |||
| * nonzero error code if unable to allocate a new registry | |||
| */ | |||
| int Shm::create_registry (jack_shm_info_t * ri) { | |||
| jack_d("create_registry\n"); | |||
| /* registry must be locked */ | |||
| int shm_fd = 0; | |||
| strncpy (registry_id, JACK_REGISTRY_NAME, sizeof (registry_id) - 1); | |||
| registry_id[sizeof (registry_id) - 1] = '\0'; | |||
| sp<IAndroidShm> service = getShmService(); | |||
| if(service == NULL){ | |||
| jack_error("shm service is null"); | |||
| return EINVAL; | |||
| } | |||
| if((shm_fd = service->allocShm(JACK_SHM_REGISTRY_SIZE)) < 0) { | |||
| jack_error("Cannot create shm registry segment"); | |||
| registry_fd = JACK_SHM_REGISTRY_FD; | |||
| return EINVAL; | |||
| } | |||
| service->setRegistryIndex(shm_fd); | |||
| /* set up global pointers */ | |||
| ri->fd = shm_fd; | |||
| ri->index = JACK_SHM_REGISTRY_INDEX; | |||
| registry_fd = shm_fd; | |||
| ri->ptr.attached_at = shm_addr(shm_fd); | |||
| ri->size = JACK_SHM_REGISTRY_SIZE; | |||
| jack_shm_header = (jack_shm_header_t*)(ri->ptr.attached_at); | |||
| jack_shm_registry = (jack_shm_registry_t *) (jack_shm_header + 1); | |||
| jack_d("create_registry jack_shm_header[%p], jack_shm_registry[%p]", jack_shm_header, jack_shm_registry); | |||
| /* initialize registry contents */ | |||
| shm_init_registry (); | |||
| //close (shm_fd); // steph | |||
| return 0; | |||
| } | |||
| int Shm::shm_validate_registry () { | |||
| /* registry must be locked */ | |||
| if(jack_shm_header == NULL) { | |||
| return -1; | |||
| } | |||
| if ((jack_shm_header->magic == JACK_SHM_MAGIC) | |||
| //&& (jack_shm_header->protocol == JACK_PROTOCOL_VERSION) | |||
| && (jack_shm_header->type == jack_shmtype) | |||
| && (jack_shm_header->size == JACK_SHM_REGISTRY_SIZE) | |||
| && (jack_shm_header->hdr_len == sizeof (jack_shm_header_t)) | |||
| && (jack_shm_header->entry_len == sizeof (jack_shm_registry_t))) { | |||
| return 0; /* registry OK */ | |||
| } | |||
| return -1; | |||
| } | |||
| int Shm::server_initialize_shm (int new_registry) { | |||
| int rc; | |||
| jack_d("server_initialize_shm\n"); | |||
| if (jack_shm_header) | |||
| return 0; /* already initialized */ | |||
| if (shm_lock_registry () < 0) { | |||
| jack_error ("jack_shm_lock_registry fails..."); | |||
| return -1; | |||
| } | |||
| rc = access_registry (®istry_info); | |||
| if (new_registry) { | |||
| remove_shm (®istry_id); | |||
| rc = ENOENT; | |||
| } | |||
| switch (rc) { | |||
| case ENOENT: /* registry does not exist */ | |||
| rc = create_registry (®istry_info); | |||
| break; | |||
| case 0: /* existing registry */ | |||
| if (shm_validate_registry () == 0) | |||
| break; | |||
| /* else it was invalid, so fall through */ | |||
| case EINVAL: /* bad registry */ | |||
| /* Apparently, this registry was created by an older | |||
| * JACK version. Delete it so we can try again. */ | |||
| release_shm (®istry_info); | |||
| remove_shm (®istry_id); | |||
| if ((rc = create_registry (®istry_info)) != 0) { | |||
| //jack_error ("incompatible shm registry (%s)", | |||
| // strerror (errno)); | |||
| jack_error ("incompatible shm registry"); | |||
| //#ifndef USE_POSIX_SHM | |||
| // jack_error ("to delete, use `ipcrm -M 0x%0.8x'", JACK_SHM_REGISTRY_KEY); | |||
| //#endif | |||
| } | |||
| break; | |||
| default: /* failure return code */ | |||
| break; | |||
| } | |||
| shm_unlock_registry (); | |||
| return rc; | |||
| } | |||
| // here begin the API | |||
| int Shm::register_server (const char *server_name, int new_registry) { | |||
| int i, res = 0; | |||
| jack_d("register_server new_registry[%d]\n", new_registry); | |||
| set_server_prefix (server_name); | |||
| if (server_initialize_shm (new_registry)) | |||
| return ENOMEM; | |||
| if (shm_lock_registry () < 0) { | |||
| jack_error ("jack_shm_lock_registry fails..."); | |||
| return -1; | |||
| } | |||
| /* See if server_name already registered. Since server names | |||
| * are per-user, we register the unique server prefix string. | |||
| */ | |||
| for (i = 0; i < MAX_SERVERS; i++) { | |||
| if (strncmp (jack_shm_header->server[i].name, | |||
| jack_shm_server_prefix, | |||
| JACK_SERVER_NAME_SIZE) != 0) | |||
| continue; /* no match */ | |||
| if (jack_shm_header->server[i].pid == GetPID()) { | |||
| res = 0; /* it's me */ | |||
| goto unlock; | |||
| } | |||
| /* see if server still exists */ | |||
| if (kill (jack_shm_header->server[i].pid, 0) == 0) { | |||
| res = EEXIST; /* other server running */ | |||
| goto unlock; | |||
| } | |||
| /* it's gone, reclaim this entry */ | |||
| memset (&jack_shm_header->server[i], 0, | |||
| sizeof (jack_shm_server_t)); | |||
| } | |||
| /* find a free entry */ | |||
| for (i = 0; i < MAX_SERVERS; i++) { | |||
| if (jack_shm_header->server[i].pid == 0) | |||
| break; | |||
| } | |||
| if (i >= MAX_SERVERS) { | |||
| res = ENOSPC; /* out of space */ | |||
| goto unlock; | |||
| } | |||
| /* claim it */ | |||
| jack_shm_header->server[i].pid = GetPID(); | |||
| strncpy (jack_shm_header->server[i].name, | |||
| jack_shm_server_prefix, | |||
| JACK_SERVER_NAME_SIZE - 1); | |||
| jack_shm_header->server[i].name[JACK_SERVER_NAME_SIZE - 1] = '\0'; | |||
| unlock: | |||
| shm_unlock_registry (); | |||
| return res; | |||
| } | |||
| int Shm::unregister_server (const char * /* server_name */) { | |||
| int i; | |||
| if (shm_lock_registry () < 0) { | |||
| jack_error ("jack_shm_lock_registry fails..."); | |||
| return -1; | |||
| } | |||
| for (i = 0; i < MAX_SERVERS; i++) { | |||
| if (jack_shm_header->server[i].pid == GetPID()) { | |||
| memset (&jack_shm_header->server[i], 0, | |||
| sizeof (jack_shm_server_t)); | |||
| } | |||
| } | |||
| shm_unlock_registry (); | |||
| return 0; | |||
| } | |||
| int Shm::initialize_shm (const char *server_name) { | |||
| int rc; | |||
| if (jack_shm_header) | |||
| return 0; /* already initialized */ | |||
| set_server_prefix (server_name); | |||
| if (shm_lock_registry () < 0) { | |||
| jack_error ("jack_shm_lock_registry fails..."); | |||
| return -1; | |||
| } | |||
| if ((rc = access_registry (®istry_info)) == 0) { | |||
| if ((rc = shm_validate_registry ()) != 0) { | |||
| jack_error ("Incompatible shm registry, " | |||
| "are jackd and libjack in sync?"); | |||
| } | |||
| } | |||
| shm_unlock_registry (); | |||
| return rc; | |||
| } | |||
| int Shm::initialize_shm_server (void) { | |||
| // not used | |||
| return 0; | |||
| } | |||
| int Shm::initialize_shm_client (void) { | |||
| // not used | |||
| return 0; | |||
| } | |||
| int Shm::cleanup_shm (void) { | |||
| int i; | |||
| int destroy; | |||
| jack_shm_info_t copy; | |||
| if (shm_lock_registry () < 0) { | |||
| jack_error ("jack_shm_lock_registry fails..."); | |||
| return -1; | |||
| } | |||
| for (i = 0; i < MAX_SHM_ID; i++) { | |||
| jack_shm_registry_t* r; | |||
| r = &jack_shm_registry[i]; | |||
| memcpy (©, r, sizeof (jack_shm_info_t)); | |||
| destroy = FALSE; | |||
| /* ignore unused entries */ | |||
| if (r->allocator == 0) | |||
| continue; | |||
| /* is this my shm segment? */ | |||
| if (r->allocator == GetPID()) { | |||
| /* allocated by this process, so unattach | |||
| and destroy. */ | |||
| release_shm (©); | |||
| destroy = TRUE; | |||
| } else { | |||
| /* see if allocator still exists */ | |||
| if (kill (r->allocator, 0)) { | |||
| if (errno == ESRCH) { | |||
| /* allocator no longer exists, | |||
| * so destroy */ | |||
| destroy = TRUE; | |||
| } | |||
| } | |||
| } | |||
| if (destroy) { | |||
| int index = copy.index; | |||
| if ((index >= 0) && (index < MAX_SHM_ID)) { | |||
| remove_shm (&jack_shm_registry[index].id); | |||
| release_shm_entry (index); | |||
| } | |||
| r->size = 0; | |||
| r->allocator = 0; | |||
| } | |||
| } | |||
| shm_unlock_registry (); | |||
| return TRUE; | |||
| } | |||
| jack_shm_registry_t * Shm::get_free_shm_info () { | |||
| /* registry must be locked */ | |||
| jack_shm_registry_t* si = NULL; | |||
| int i; | |||
| for (i = 0; i < MAX_SHM_ID; ++i) { | |||
| if (jack_shm_registry[i].size == 0) { | |||
| break; | |||
| } | |||
| } | |||
| if (i < MAX_SHM_ID) { | |||
| si = &jack_shm_registry[i]; | |||
| } | |||
| return si; | |||
| } | |||
| int Shm::shmalloc (const char * /*shm_name*/, jack_shmsize_t size, jack_shm_info_t* si) { | |||
| jack_shm_registry_t* registry; | |||
| int shm_fd; | |||
| int rc = -1; | |||
| char name[SHM_NAME_MAX+1]; | |||
| if (shm_lock_registry () < 0) { | |||
| jack_error ("jack_shm_lock_registry fails..."); | |||
| return -1; | |||
| } | |||
| sp<IAndroidShm> service = getShmService(); | |||
| if(service == NULL){ | |||
| rc = errno; | |||
| jack_error("shm service is null"); | |||
| goto unlock; | |||
| } | |||
| if ((registry = get_free_shm_info ()) == NULL) { | |||
| jack_error ("shm registry full"); | |||
| goto unlock; | |||
| } | |||
| snprintf (name, sizeof (name), "/jack-%d-%d", GetUID(), registry->index); | |||
| if (strlen (name) >= sizeof (registry->id)) { | |||
| jack_error ("shm segment name too long %s", name); | |||
| goto unlock; | |||
| } | |||
| if((shm_fd = service->allocShm(size)) < 0) { | |||
| rc = errno; | |||
| jack_error ("Cannot create shm segment %s", name); | |||
| goto unlock; | |||
| } | |||
| //close (shm_fd); | |||
| registry->size = size; | |||
| strncpy (registry->id, name, sizeof (registry->id) - 1); | |||
| registry->id[sizeof (registry->id) - 1] = '\0'; | |||
| registry->allocator = GetPID(); | |||
| registry->fd = shm_fd; | |||
| si->fd = shm_fd; | |||
| si->index = registry->index; | |||
| si->ptr.attached_at = MAP_FAILED; /* not attached */ | |||
| rc = 0; /* success */ | |||
| jack_d ("[APA] jack_shmalloc : ok "); | |||
| unlock: | |||
| shm_unlock_registry (); | |||
| return rc; | |||
| } | |||
| void Shm::release_shm (jack_shm_info_t* /*si*/) { | |||
| // do nothing | |||
| } | |||
| void Shm::release_lib_shm (jack_shm_info_t* /*si*/) { | |||
| // do nothing | |||
| } | |||
| void Shm::destroy_shm (jack_shm_info_t* si) { | |||
| /* must NOT have the registry locked */ | |||
| if (si->index == JACK_SHM_NULL_INDEX) | |||
| return; /* segment not allocated */ | |||
| remove_shm (&jack_shm_registry[si->index].id); | |||
| release_shm_info (si->index); | |||
| } | |||
| int Shm::attach_shm (jack_shm_info_t* si) { | |||
| jack_shm_registry_t *registry = &jack_shm_registry[si->index]; | |||
| if((si->ptr.attached_at = shm_addr(registry->fd)) == NULL) { | |||
| jack_error ("Cannot mmap shm segment %s", registry->id); | |||
| close (si->fd); | |||
| return -1; | |||
| } | |||
| return 0; | |||
| } | |||
| int Shm::attach_lib_shm (jack_shm_info_t* si) { | |||
| int res = attach_shm(si); | |||
| if (res == 0) | |||
| si->size = jack_shm_registry[si->index].size; // Keep size in si struct | |||
| return res; | |||
| } | |||
| int Shm::attach_shm_read (jack_shm_info_t* si) { | |||
| jack_shm_registry_t *registry = &jack_shm_registry[si->index]; | |||
| if((si->ptr.attached_at = shm_addr(registry->fd)) == NULL) { | |||
| jack_error ("Cannot mmap shm segment %s", registry->id); | |||
| close (si->fd); | |||
| return -1; | |||
| } | |||
| return 0; | |||
| } | |||
| int Shm::attach_lib_shm_read (jack_shm_info_t* si) { | |||
| int res = attach_shm_read(si); | |||
| if (res == 0) | |||
| si->size = jack_shm_registry[si->index].size; // Keep size in si struct | |||
| return res; | |||
| } | |||
| int Shm::resize_shm (jack_shm_info_t* si, jack_shmsize_t size) { | |||
| jack_shm_id_t id; | |||
| /* The underlying type of `id' differs for SYSV and POSIX */ | |||
| memcpy (&id, &jack_shm_registry[si->index].id, sizeof (id)); | |||
| release_shm (si); | |||
| destroy_shm (si); | |||
| if (shmalloc ((char *) id, size, si)) { | |||
| return -1; | |||
| } | |||
| return attach_shm (si); | |||
| } | |||
| void Shm::jack_shm_copy_from_registry (jack_shm_info_t* si, jack_shm_registry_index_t t) { | |||
| Shm::Instantiate()->shm_copy_from_registry(si,t); | |||
| } | |||
| void Shm::jack_shm_copy_to_registry (jack_shm_info_t* si, jack_shm_registry_index_t* t) { | |||
| Shm::Instantiate()->shm_copy_to_registry(si,t); | |||
| } | |||
| int Shm::jack_release_shm_info (jack_shm_registry_index_t t) { | |||
| return Shm::Instantiate()->release_shm_info(t); | |||
| } | |||
| char* Shm::jack_shm_addr (jack_shm_info_t* si) { | |||
| if(si != NULL) { | |||
| return (char*)si->ptr.attached_at; | |||
| } else { | |||
| jack_error ("jack_shm_addr : jack_shm_info_t is NULL!"); | |||
| return NULL; | |||
| } | |||
| } | |||
| int Shm::jack_register_server (const char *server_name, int new_registry) { | |||
| return Shm::Instantiate()->register_server(server_name, new_registry); | |||
| } | |||
| int Shm::jack_unregister_server (const char *server_name) { | |||
| return Shm::Instantiate()->unregister_server(server_name); | |||
| } | |||
| int Shm::jack_initialize_shm (const char *server_name) { | |||
| return Shm::Instantiate()->initialize_shm(server_name); | |||
| } | |||
| int Shm::jack_initialize_shm_server (void) { | |||
| return Shm::Instantiate()->initialize_shm_server(); | |||
| } | |||
| int Shm::jack_initialize_shm_client () { | |||
| return Shm::Instantiate()->initialize_shm_client(); | |||
| } | |||
| int Shm::jack_cleanup_shm (void) { | |||
| return Shm::Instantiate()->cleanup_shm(); | |||
| } | |||
| int Shm::jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* result) { | |||
| return Shm::Instantiate()->shmalloc(shm_name, size, result); | |||
| } | |||
| void Shm::jack_release_shm (jack_shm_info_t* si) { | |||
| Shm::Instantiate()->release_shm(si); | |||
| } | |||
| void Shm::jack_release_lib_shm (jack_shm_info_t* si) { | |||
| Shm::Instantiate()->release_lib_shm(si); | |||
| } | |||
| void Shm::jack_destroy_shm (jack_shm_info_t* si) { | |||
| Shm::Instantiate()->destroy_shm(si); | |||
| } | |||
| int Shm::jack_attach_shm (jack_shm_info_t* si) { | |||
| return Shm::Instantiate()->attach_shm(si); | |||
| } | |||
| int Shm::jack_attach_lib_shm (jack_shm_info_t* si) { | |||
| return Shm::Instantiate()->attach_lib_shm(si); | |||
| } | |||
| int Shm::jack_attach_shm_read (jack_shm_info_t* si) { | |||
| return Shm::Instantiate()->attach_shm_read(si); | |||
| } | |||
| int Shm::jack_attach_lib_shm_read (jack_shm_info_t* si) { | |||
| return Shm::Instantiate()->attach_lib_shm_read(si); | |||
| } | |||
| int Shm::jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size) { | |||
| return Shm::Instantiate()->resize_shm(si, size); | |||
| } | |||
| }; | |||
| void jack_shm_copy_from_registry (jack_shm_info_t* si, jack_shm_registry_index_t t) { | |||
| android::Shm::jack_shm_copy_from_registry(si, t); | |||
| } | |||
| void jack_shm_copy_to_registry (jack_shm_info_t* si, jack_shm_registry_index_t* t) { | |||
| android::Shm::jack_shm_copy_to_registry(si, t); | |||
| } | |||
| int jack_release_shm_info (jack_shm_registry_index_t t) { | |||
| return android::Shm::jack_release_shm_info(t); | |||
| } | |||
| char* jack_shm_addr (jack_shm_info_t* si) { | |||
| return android::Shm::jack_shm_addr(si); | |||
| } | |||
| int jack_register_server (const char *server_name, int new_registry) { | |||
| return android::Shm::jack_register_server(server_name, new_registry); | |||
| } | |||
| int jack_unregister_server (const char *server_name) { | |||
| return android::Shm::jack_unregister_server(server_name); | |||
| } | |||
| int jack_initialize_shm (const char *server_name) { | |||
| return android::Shm::jack_initialize_shm(server_name); | |||
| } | |||
| int jack_initialize_shm_server (void) { | |||
| return android::Shm::jack_initialize_shm_server(); | |||
| } | |||
| int jack_initialize_shm_client (void) { | |||
| return android::Shm::jack_initialize_shm_client(); | |||
| } | |||
| int jack_cleanup_shm (void) { | |||
| return android::Shm::jack_cleanup_shm(); | |||
| } | |||
| int jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* result) { | |||
| return android::Shm::jack_shmalloc(shm_name, size, result); | |||
| } | |||
| void jack_release_shm (jack_shm_info_t* si) { | |||
| android::Shm::jack_release_shm(si); | |||
| } | |||
| void jack_release_lib_shm (jack_shm_info_t* si) { | |||
| android::Shm::jack_release_lib_shm(si); | |||
| } | |||
| void jack_destroy_shm (jack_shm_info_t* si) { | |||
| android::Shm::jack_destroy_shm(si); | |||
| } | |||
| int jack_attach_shm (jack_shm_info_t* si) { | |||
| return android::Shm::jack_attach_shm(si); | |||
| } | |||
| int jack_attach_lib_shm (jack_shm_info_t* si) { | |||
| return android::Shm::jack_attach_lib_shm(si); | |||
| } | |||
| int jack_attach_shm_read (jack_shm_info_t* si) { | |||
| return android::Shm::jack_attach_shm_read(si); | |||
| } | |||
| int jack_attach_lib_shm_read (jack_shm_info_t* si) { | |||
| return android::Shm::jack_attach_lib_shm_read(si); | |||
| } | |||
| int jack_resize_shm (jack_shm_info_t* si, jack_shmsize_t size) { | |||
| return android::Shm::jack_resize_shm(si, size); | |||
| } | |||
| void jack_instantiate() { | |||
| android::AndroidShm::instantiate(); | |||
| } | |||
| @@ -0,0 +1,144 @@ | |||
| /* | |||
| Copyright (C) 2001-2003 Paul Davis | |||
| Copyright (C) 2005-2012 Grame | |||
| Copyright (C) 2013 Samsung Electronics | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU Lesser General Public License as published by | |||
| the Free Software Foundation; either version 2.1 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| #ifndef __jack_shm_android_h__ | |||
| #define __jack_shm_android_h__ | |||
| #include <limits.h> | |||
| #include <sys/types.h> | |||
| #include "types.h" | |||
| #include "JackCompilerDeps.h" | |||
| #include <binder/MemoryHeapBase.h> | |||
| #include <utils/RefBase.h> | |||
| #ifdef __cplusplus | |||
| extern "C" | |||
| { | |||
| #endif | |||
| #define JACK_SHM_REGISTRY_FD -1 | |||
| #define JACK_SHM_HEAP_ENOUGH_COUNT 300 | |||
| void jack_instantiate(); | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| namespace android { | |||
| class IAndroidShm; | |||
| class Shm { | |||
| public: | |||
| static Shm* Instantiate(); | |||
| virtual ~Shm(); | |||
| private: | |||
| Shm(); | |||
| Shm( const Shm&); | |||
| Shm& operator=(const Shm); | |||
| private: | |||
| void set_server_prefix (const char *server_name); | |||
| int server_initialize_shm (int new_registry); | |||
| int shm_lock_registry (void); | |||
| void shm_unlock_registry (void); | |||
| int access_registry (jack_shm_info_t *ri); | |||
| void remove_shm (jack_shm_id_t *id); | |||
| int create_registry (jack_shm_info_t *ri); | |||
| int shm_validate_registry (); | |||
| int GetUID(); | |||
| int GetPID(); | |||
| void shm_init_registry (); | |||
| void release_shm_entry (jack_shm_registry_index_t index); | |||
| jack_shm_registry_t * get_free_shm_info (); | |||
| public: | |||
| static void jack_shm_copy_from_registry (jack_shm_info_t*, jack_shm_registry_index_t); | |||
| static void jack_shm_copy_to_registry (jack_shm_info_t*, jack_shm_registry_index_t*); | |||
| static int jack_release_shm_info (jack_shm_registry_index_t); | |||
| static char* jack_shm_addr (jack_shm_info_t* si); | |||
| static int jack_register_server (const char *server_name, int new_registry); | |||
| static int jack_unregister_server (const char *server_name); | |||
| static int jack_initialize_shm (const char *server_name); | |||
| static int jack_initialize_shm_server (void); | |||
| static int jack_initialize_shm_client (void); | |||
| static int jack_cleanup_shm (void); | |||
| static int jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* result); | |||
| static void jack_release_shm (jack_shm_info_t*); | |||
| static void jack_release_lib_shm (jack_shm_info_t*); | |||
| static void jack_destroy_shm (jack_shm_info_t*); | |||
| static int jack_attach_shm (jack_shm_info_t*); | |||
| static int jack_attach_lib_shm (jack_shm_info_t*); | |||
| static int jack_attach_shm_read (jack_shm_info_t*); | |||
| static int jack_attach_lib_shm_read (jack_shm_info_t*); | |||
| static int jack_resize_shm (jack_shm_info_t*, jack_shmsize_t size); | |||
| public: | |||
| void shm_copy_from_registry (jack_shm_info_t*, jack_shm_registry_index_t); | |||
| void shm_copy_to_registry (jack_shm_info_t*, jack_shm_registry_index_t*); | |||
| int release_shm_info (jack_shm_registry_index_t); | |||
| char* shm_addr (unsigned int fd); | |||
| // here begin the API | |||
| int register_server (const char *server_name, int new_registry); | |||
| int unregister_server (const char *server_name); | |||
| int initialize_shm (const char *server_name); | |||
| int initialize_shm_server (void); | |||
| int initialize_shm_client (void); | |||
| int cleanup_shm (void); | |||
| int shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* result); | |||
| void release_shm (jack_shm_info_t*); | |||
| void release_lib_shm (jack_shm_info_t*); | |||
| void destroy_shm (jack_shm_info_t*); | |||
| int attach_shm (jack_shm_info_t*); | |||
| int attach_lib_shm (jack_shm_info_t*); | |||
| int attach_shm_read (jack_shm_info_t*); | |||
| int attach_lib_shm_read (jack_shm_info_t*); | |||
| int resize_shm (jack_shm_info_t*, jack_shmsize_t size); | |||
| private: | |||
| static jack_shmtype_t jack_shmtype; | |||
| static jack_shm_id_t registry_id; | |||
| static jack_shm_fd_t registry_fd; | |||
| static jack_shm_info_t registry_info; | |||
| static jack_shm_header_t *jack_shm_header; | |||
| static jack_shm_registry_t *jack_shm_registry; | |||
| static char jack_shm_server_prefix[JACK_SERVER_NAME_SIZE]; | |||
| static int semid; | |||
| static pthread_mutex_t mutex; | |||
| static Shm* ref; | |||
| void jack_release_shm_entry (jack_shm_registry_index_t index); | |||
| int jack_shm_lock_registry (void); | |||
| void jack_shm_unlock_registry (void); | |||
| //static sp<IAndroidShm> mShmService; | |||
| static sp<IMemoryHeap> mShmMemBase[JACK_SHM_HEAP_ENOUGH_COUNT]; | |||
| public: | |||
| static sp<IAndroidShm> getShmService(); | |||
| }; | |||
| }; | |||
| #endif /* __jack_shm_android_h__ */ | |||
| @@ -0,0 +1,25 @@ | |||
| /* Configuration header created by Waf - do not edit */ | |||
| #ifndef _CONFIG_H_WAF | |||
| #define _CONFIG_H_WAF | |||
| /* #define HAVE_SAMPLERATE 0 */ | |||
| /* #define HAVE_PPOLL 0 */ | |||
| /* #define HAVE_SNDFILE */ | |||
| /* #define HAVE_NCURSES 0 */ | |||
| /* #define HAVE_CELT 0 */ | |||
| /* #define HAVE_CELT_API_0_11 0 */ | |||
| /* #define HAVE_CELT_API_0_8 0 */ | |||
| /* #define HAVE_CELT_API_0_7 0 */ | |||
| /* #define HAVE_CELT_API_0_5 0 */ | |||
| /* #define HAVE_READLINE 0 */ | |||
| #define CLIENT_NUM 16 | |||
| #define PORT_NUM_FOR_CLIENT 16 | |||
| #define PORT_NUM 128 | |||
| #define PORT_NUM_MAX 256 | |||
| #define ADDON_DIR "/system/lib/jack" | |||
| #define JACK_LOCATION "/system/bin" | |||
| #define JACKMP 1 | |||
| /* #define USE_POSIX_SHM 0 */ | |||
| /* #define __CLIENTDEBUG__ 1 */ | |||
| #endif /* _CONFIG_H_WAF */ | |||
| @@ -0,0 +1,14 @@ | |||
| //fix build error in KitKat | |||
| #define _U _CTYPE_U | |||
| #define _L _CTYPE_L | |||
| #define _N _CTYPE_N | |||
| #define _S _CTYPE_S | |||
| #define _P _CTYPE_P | |||
| #define _C _CTYPE_C | |||
| #define _X _CTYPE_X | |||
| #define _B _CTYPE_B | |||
| #include <../../../../../../../../../../../prebuilts/ndk/current/sources/cxx-stl/gnu-libstdc++/libs/armeabi-v7a/include/bits/ctype_base.h> | |||
| @@ -0,0 +1,539 @@ | |||
| /* | |||
| opensl_io.c: | |||
| Android OpenSL input/output module | |||
| Copyright (c) 2012, Victor Lazzarini | |||
| All rights reserved. | |||
| Redistribution and use in source and binary forms, with or without | |||
| modification, are permitted provided that the following conditions are met: | |||
| * Redistributions of source code must retain the above copyright | |||
| notice, this list of conditions and the following disclaimer. | |||
| * Redistributions in binary form must reproduce the above copyright | |||
| notice, this list of conditions and the following disclaimer in the | |||
| documentation and/or other materials provided with the distribution. | |||
| * Neither the name of the <organization> nor the | |||
| names of its contributors may be used to endorse or promote products | |||
| derived from this software without specific prior written permission. | |||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY | |||
| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| */ | |||
| #include "opensl_io.h" | |||
| //#define CONV16BIT 32768 | |||
| //#define CONVMYFLT (1./32768.) | |||
| #define CONV16BIT 32640 | |||
| #define CONVMYFLT (1./32640.) | |||
| static void* createThreadLock(void); | |||
| static int waitThreadLock(void *lock); | |||
| static void notifyThreadLock(void *lock); | |||
| static void destroyThreadLock(void *lock); | |||
| static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context); | |||
| static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context); | |||
| // creates the OpenSL ES audio engine | |||
| static SLresult openSLCreateEngine(OPENSL_STREAM *p) | |||
| { | |||
| SLresult result; | |||
| // create engine | |||
| result = slCreateEngine(&(p->engineObject), 0, NULL, 0, NULL, NULL); | |||
| if(result != SL_RESULT_SUCCESS) goto engine_end; | |||
| // realize the engine | |||
| result = (*p->engineObject)->Realize(p->engineObject, SL_BOOLEAN_FALSE); | |||
| if(result != SL_RESULT_SUCCESS) goto engine_end; | |||
| // get the engine interface, which is needed in order to create other objects | |||
| result = (*p->engineObject)->GetInterface(p->engineObject, SL_IID_ENGINE, &(p->engineEngine)); | |||
| if(result != SL_RESULT_SUCCESS) goto engine_end; | |||
| engine_end: | |||
| return result; | |||
| } | |||
| // opens the OpenSL ES device for output | |||
| static SLresult openSLPlayOpen(OPENSL_STREAM *p) | |||
| { | |||
| SLresult result; | |||
| SLuint32 sr = p->sr; | |||
| SLuint32 channels = p->outchannels; | |||
| if(channels){ | |||
| // configure audio source | |||
| SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; | |||
| switch(sr){ | |||
| case 8000: | |||
| sr = SL_SAMPLINGRATE_8; | |||
| break; | |||
| case 11025: | |||
| sr = SL_SAMPLINGRATE_11_025; | |||
| break; | |||
| case 16000: | |||
| sr = SL_SAMPLINGRATE_16; | |||
| break; | |||
| case 22050: | |||
| sr = SL_SAMPLINGRATE_22_05; | |||
| break; | |||
| case 24000: | |||
| sr = SL_SAMPLINGRATE_24; | |||
| break; | |||
| case 32000: | |||
| sr = SL_SAMPLINGRATE_32; | |||
| break; | |||
| case 44100: | |||
| sr = SL_SAMPLINGRATE_44_1; | |||
| break; | |||
| case 48000: | |||
| sr = SL_SAMPLINGRATE_48; | |||
| break; | |||
| case 64000: | |||
| sr = SL_SAMPLINGRATE_64; | |||
| break; | |||
| case 88200: | |||
| sr = SL_SAMPLINGRATE_88_2; | |||
| break; | |||
| case 96000: | |||
| sr = SL_SAMPLINGRATE_96; | |||
| break; | |||
| case 192000: | |||
| sr = SL_SAMPLINGRATE_192; | |||
| break; | |||
| default: | |||
| return -1; | |||
| } | |||
| const SLInterfaceID ids[] = {SL_IID_VOLUME}; | |||
| const SLboolean req[] = {SL_BOOLEAN_FALSE}; | |||
| result = (*p->engineEngine)->CreateOutputMix(p->engineEngine, &(p->outputMixObject), 1, ids, req); | |||
| if(result != SL_RESULT_SUCCESS) goto end_openaudio; | |||
| // realize the output mix | |||
| result = (*p->outputMixObject)->Realize(p->outputMixObject, SL_BOOLEAN_FALSE); | |||
| int speakers; | |||
| if(channels > 1) | |||
| speakers = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; | |||
| else speakers = SL_SPEAKER_FRONT_CENTER; | |||
| SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM,channels, sr, | |||
| SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, | |||
| speakers, SL_BYTEORDER_LITTLEENDIAN}; | |||
| SLDataSource audioSrc = {&loc_bufq, &format_pcm}; | |||
| // configure audio sink | |||
| SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, p->outputMixObject}; | |||
| SLDataSink audioSnk = {&loc_outmix, NULL}; | |||
| // create audio player | |||
| const SLInterfaceID ids1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; | |||
| const SLboolean req1[] = {SL_BOOLEAN_TRUE}; | |||
| result = (*p->engineEngine)->CreateAudioPlayer(p->engineEngine, &(p->bqPlayerObject), &audioSrc, &audioSnk, | |||
| 1, ids1, req1); | |||
| if(result != SL_RESULT_SUCCESS) goto end_openaudio; | |||
| // realize the player | |||
| result = (*p->bqPlayerObject)->Realize(p->bqPlayerObject, SL_BOOLEAN_FALSE); | |||
| if(result != SL_RESULT_SUCCESS) goto end_openaudio; | |||
| // get the play interface | |||
| result = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_PLAY, &(p->bqPlayerPlay)); | |||
| if(result != SL_RESULT_SUCCESS) goto end_openaudio; | |||
| // get the buffer queue interface | |||
| result = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, | |||
| &(p->bqPlayerBufferQueue)); | |||
| if(result != SL_RESULT_SUCCESS) goto end_openaudio; | |||
| // register callback on the buffer queue | |||
| result = (*p->bqPlayerBufferQueue)->RegisterCallback(p->bqPlayerBufferQueue, bqPlayerCallback, p); | |||
| if(result != SL_RESULT_SUCCESS) goto end_openaudio; | |||
| // set the player's state to playing | |||
| result = (*p->bqPlayerPlay)->SetPlayState(p->bqPlayerPlay, SL_PLAYSTATE_PLAYING); | |||
| end_openaudio: | |||
| return result; | |||
| } | |||
| return SL_RESULT_SUCCESS; | |||
| } | |||
| // Open the OpenSL ES device for input | |||
| static SLresult openSLRecOpen(OPENSL_STREAM *p){ | |||
| SLresult result; | |||
| SLuint32 sr = p->sr; | |||
| SLuint32 channels = p->inchannels; | |||
| if(channels){ | |||
| switch(sr){ | |||
| case 8000: | |||
| sr = SL_SAMPLINGRATE_8; | |||
| break; | |||
| case 11025: | |||
| sr = SL_SAMPLINGRATE_11_025; | |||
| break; | |||
| case 16000: | |||
| sr = SL_SAMPLINGRATE_16; | |||
| break; | |||
| case 22050: | |||
| sr = SL_SAMPLINGRATE_22_05; | |||
| break; | |||
| case 24000: | |||
| sr = SL_SAMPLINGRATE_24; | |||
| break; | |||
| case 32000: | |||
| sr = SL_SAMPLINGRATE_32; | |||
| break; | |||
| case 44100: | |||
| sr = SL_SAMPLINGRATE_44_1; | |||
| break; | |||
| case 48000: | |||
| sr = SL_SAMPLINGRATE_48; | |||
| break; | |||
| case 64000: | |||
| sr = SL_SAMPLINGRATE_64; | |||
| break; | |||
| case 88200: | |||
| sr = SL_SAMPLINGRATE_88_2; | |||
| break; | |||
| case 96000: | |||
| sr = SL_SAMPLINGRATE_96; | |||
| break; | |||
| case 192000: | |||
| sr = SL_SAMPLINGRATE_192; | |||
| break; | |||
| default: | |||
| return -1; | |||
| } | |||
| // configure audio source | |||
| SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, | |||
| SL_DEFAULTDEVICEID_AUDIOINPUT, NULL}; | |||
| SLDataSource audioSrc = {&loc_dev, NULL}; | |||
| // configure audio sink | |||
| int speakers; | |||
| if(channels > 1) | |||
| speakers = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; | |||
| else speakers = SL_SPEAKER_FRONT_CENTER; | |||
| SLDataLocator_AndroidSimpleBufferQueue loc_bq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; | |||
| SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, channels, sr, | |||
| SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, | |||
| speakers, SL_BYTEORDER_LITTLEENDIAN}; | |||
| SLDataSink audioSnk = {&loc_bq, &format_pcm}; | |||
| // create audio recorder | |||
| // (requires the RECORD_AUDIO permission) | |||
| const SLInterfaceID id[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; | |||
| const SLboolean req[1] = {SL_BOOLEAN_TRUE}; | |||
| result = (*p->engineEngine)->CreateAudioRecorder(p->engineEngine, &(p->recorderObject), &audioSrc, | |||
| &audioSnk, 1, id, req); | |||
| if (SL_RESULT_SUCCESS != result) goto end_recopen; | |||
| // realize the audio recorder | |||
| result = (*p->recorderObject)->Realize(p->recorderObject, SL_BOOLEAN_FALSE); | |||
| if (SL_RESULT_SUCCESS != result) goto end_recopen; | |||
| // get the record interface | |||
| result = (*p->recorderObject)->GetInterface(p->recorderObject, SL_IID_RECORD, &(p->recorderRecord)); | |||
| if (SL_RESULT_SUCCESS != result) goto end_recopen; | |||
| // get the buffer queue interface | |||
| result = (*p->recorderObject)->GetInterface(p->recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, | |||
| &(p->recorderBufferQueue)); | |||
| if (SL_RESULT_SUCCESS != result) goto end_recopen; | |||
| // register callback on the buffer queue | |||
| result = (*p->recorderBufferQueue)->RegisterCallback(p->recorderBufferQueue, bqRecorderCallback, | |||
| p); | |||
| if (SL_RESULT_SUCCESS != result) goto end_recopen; | |||
| result = (*p->recorderRecord)->SetRecordState(p->recorderRecord, SL_RECORDSTATE_RECORDING); | |||
| end_recopen: | |||
| return result; | |||
| } | |||
| else return SL_RESULT_SUCCESS; | |||
| } | |||
| // close the OpenSL IO and destroy the audio engine | |||
| static void openSLDestroyEngine(OPENSL_STREAM *p){ | |||
| // destroy buffer queue audio player object, and invalidate all associated interfaces | |||
| if (p->bqPlayerObject != NULL) { | |||
| (*p->bqPlayerObject)->Destroy(p->bqPlayerObject); | |||
| p->bqPlayerObject = NULL; | |||
| p->bqPlayerPlay = NULL; | |||
| p->bqPlayerBufferQueue = NULL; | |||
| p->bqPlayerEffectSend = NULL; | |||
| } | |||
| // destroy audio recorder object, and invalidate all associated interfaces | |||
| if (p->recorderObject != NULL) { | |||
| (*p->recorderObject)->Destroy(p->recorderObject); | |||
| p->recorderObject = NULL; | |||
| p->recorderRecord = NULL; | |||
| p->recorderBufferQueue = NULL; | |||
| } | |||
| // destroy output mix object, and invalidate all associated interfaces | |||
| if (p->outputMixObject != NULL) { | |||
| (*p->outputMixObject)->Destroy(p->outputMixObject); | |||
| p->outputMixObject = NULL; | |||
| } | |||
| // destroy engine object, and invalidate all associated interfaces | |||
| if (p->engineObject != NULL) { | |||
| (*p->engineObject)->Destroy(p->engineObject); | |||
| p->engineObject = NULL; | |||
| p->engineEngine = NULL; | |||
| } | |||
| } | |||
| // open the android audio device for input and/or output | |||
| OPENSL_STREAM *android_OpenAudioDevice(int sr, int inchannels, int outchannels, int bufferframes){ | |||
| OPENSL_STREAM *p; | |||
| p = (OPENSL_STREAM *) calloc(sizeof(OPENSL_STREAM),1); | |||
| p->inchannels = inchannels; | |||
| p->outchannels = outchannels; | |||
| p->sr = sr; | |||
| p->inlock = createThreadLock(); | |||
| p->outlock = createThreadLock(); | |||
| if((p->outBufSamples = bufferframes*outchannels) != 0) { | |||
| if((p->outputBuffer[0] = (short *) calloc(p->outBufSamples, sizeof(short))) == NULL || | |||
| (p->outputBuffer[1] = (short *) calloc(p->outBufSamples, sizeof(short))) == NULL) { | |||
| android_CloseAudioDevice(p); | |||
| return NULL; | |||
| } | |||
| } | |||
| if((p->inBufSamples = bufferframes*inchannels) != 0){ | |||
| if((p->inputBuffer[0] = (short *) calloc(p->inBufSamples, sizeof(short))) == NULL || | |||
| (p->inputBuffer[1] = (short *) calloc(p->inBufSamples, sizeof(short))) == NULL){ | |||
| android_CloseAudioDevice(p); | |||
| return NULL; | |||
| } | |||
| } | |||
| p->currentInputIndex = 0; | |||
| p->currentOutputBuffer = 0; | |||
| p->currentInputIndex = p->inBufSamples; | |||
| p->currentInputBuffer = 0; | |||
| if(openSLCreateEngine(p) != SL_RESULT_SUCCESS) { | |||
| android_CloseAudioDevice(p); | |||
| return NULL; | |||
| } | |||
| if(openSLRecOpen(p) != SL_RESULT_SUCCESS) { | |||
| android_CloseAudioDevice(p); | |||
| return NULL; | |||
| } | |||
| if(openSLPlayOpen(p) != SL_RESULT_SUCCESS) { | |||
| android_CloseAudioDevice(p); | |||
| return NULL; | |||
| } | |||
| notifyThreadLock(p->outlock); | |||
| notifyThreadLock(p->inlock); | |||
| p->time = 0.; | |||
| return p; | |||
| } | |||
| // close the android audio device | |||
| void android_CloseAudioDevice(OPENSL_STREAM *p){ | |||
| if (p == NULL) | |||
| return; | |||
| openSLDestroyEngine(p); | |||
| if (p->inlock != NULL) { | |||
| notifyThreadLock(p->inlock); | |||
| destroyThreadLock(p->inlock); | |||
| p->inlock = NULL; | |||
| } | |||
| if (p->outlock != NULL) { | |||
| notifyThreadLock(p->outlock); | |||
| destroyThreadLock(p->outlock); | |||
| p->inlock = NULL; | |||
| } | |||
| if (p->outputBuffer[0] != NULL) { | |||
| free(p->outputBuffer[0]); | |||
| p->outputBuffer[0] = NULL; | |||
| } | |||
| if (p->outputBuffer[1] != NULL) { | |||
| free(p->outputBuffer[1]); | |||
| p->outputBuffer[1] = NULL; | |||
| } | |||
| if (p->inputBuffer[0] != NULL) { | |||
| free(p->inputBuffer[0]); | |||
| p->inputBuffer[0] = NULL; | |||
| } | |||
| if (p->inputBuffer[1] != NULL) { | |||
| free(p->inputBuffer[1]); | |||
| p->inputBuffer[1] = NULL; | |||
| } | |||
| free(p); | |||
| } | |||
| // returns timestamp of the processed stream | |||
| double android_GetTimestamp(OPENSL_STREAM *p){ | |||
| return p->time; | |||
| } | |||
| // this callback handler is called every time a buffer finishes recording | |||
| void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context) | |||
| { | |||
| OPENSL_STREAM *p = (OPENSL_STREAM *) context; | |||
| notifyThreadLock(p->inlock); | |||
| } | |||
| // gets a buffer of size samples from the device | |||
| int android_AudioIn(OPENSL_STREAM *p,float *buffer,int size){ | |||
| short *inBuffer; | |||
| int i, bufsamps, index; | |||
| if(p == NULL) return 0; | |||
| bufsamps = p->inBufSamples; | |||
| if(bufsamps == 0) return 0; | |||
| index = p->currentInputIndex; | |||
| inBuffer = p->inputBuffer[p->currentInputBuffer]; | |||
| for(i=0; i < size; i++){ | |||
| if (index >= bufsamps) { | |||
| waitThreadLock(p->inlock); | |||
| (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, | |||
| inBuffer,bufsamps*sizeof(short)); | |||
| p->currentInputBuffer = (p->currentInputBuffer ? 0 : 1); | |||
| index = 0; | |||
| inBuffer = p->inputBuffer[p->currentInputBuffer]; | |||
| } | |||
| buffer[i] = (float) inBuffer[index++]*CONVMYFLT; | |||
| } | |||
| p->currentInputIndex = index; | |||
| if(p->outchannels == 0) p->time += (double) size/(p->sr*p->inchannels); | |||
| return i; | |||
| } | |||
| // this callback handler is called every time a buffer finishes playing | |||
| void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) | |||
| { | |||
| OPENSL_STREAM *p = (OPENSL_STREAM *) context; | |||
| notifyThreadLock(p->outlock); | |||
| } | |||
| // puts a buffer of size samples to the device | |||
| int android_AudioOut(OPENSL_STREAM *p, float *buffer,int size){ | |||
| short *outBuffer; | |||
| int i, bufsamps, index; | |||
| if(p == NULL) return 0; | |||
| bufsamps = p->outBufSamples; | |||
| if(bufsamps == 0) return 0; | |||
| index = p->currentOutputIndex; | |||
| outBuffer = p->outputBuffer[p->currentOutputBuffer]; | |||
| for(i=0; i < size; i++){ | |||
| outBuffer[index++] = (short) (buffer[i]*CONV16BIT); | |||
| if (index >= p->outBufSamples) { | |||
| waitThreadLock(p->outlock); | |||
| (*p->bqPlayerBufferQueue)->Enqueue(p->bqPlayerBufferQueue, | |||
| outBuffer,bufsamps*sizeof(short)); | |||
| p->currentOutputBuffer = (p->currentOutputBuffer ? 0 : 1); | |||
| index = 0; | |||
| outBuffer = p->outputBuffer[p->currentOutputBuffer]; | |||
| } | |||
| } | |||
| p->currentOutputIndex = index; | |||
| p->time += (double) size/(p->sr*p->outchannels); | |||
| return i; | |||
| } | |||
| //---------------------------------------------------------------------- | |||
| // thread Locks | |||
| // to ensure synchronisation between callbacks and processing code | |||
| void* createThreadLock(void) | |||
| { | |||
| threadLock *p; | |||
| p = (threadLock*) malloc(sizeof(threadLock)); | |||
| if (p == NULL) | |||
| return NULL; | |||
| memset(p, 0, sizeof(threadLock)); | |||
| if (pthread_mutex_init(&(p->m), (pthread_mutexattr_t*) NULL) != 0) { | |||
| free((void*) p); | |||
| return NULL; | |||
| } | |||
| if (pthread_cond_init(&(p->c), (pthread_condattr_t*) NULL) != 0) { | |||
| pthread_mutex_destroy(&(p->m)); | |||
| free((void*) p); | |||
| return NULL; | |||
| } | |||
| p->s = (unsigned char) 1; | |||
| return p; | |||
| } | |||
| int waitThreadLock(void *lock) | |||
| { | |||
| threadLock *p; | |||
| int retval = 0; | |||
| p = (threadLock*) lock; | |||
| pthread_mutex_lock(&(p->m)); | |||
| while (!p->s) { | |||
| pthread_cond_wait(&(p->c), &(p->m)); | |||
| } | |||
| p->s = (unsigned char) 0; | |||
| pthread_mutex_unlock(&(p->m)); | |||
| return NULL; | |||
| } | |||
| void notifyThreadLock(void *lock) | |||
| { | |||
| threadLock *p; | |||
| p = (threadLock*) lock; | |||
| pthread_mutex_lock(&(p->m)); | |||
| p->s = (unsigned char) 1; | |||
| pthread_cond_signal(&(p->c)); | |||
| pthread_mutex_unlock(&(p->m)); | |||
| return; | |||
| } | |||
| void destroyThreadLock(void *lock) | |||
| { | |||
| threadLock *p; | |||
| p = (threadLock*) lock; | |||
| if (p == NULL) | |||
| return; | |||
| notifyThreadLock(p); | |||
| pthread_cond_destroy(&(p->c)); | |||
| pthread_mutex_destroy(&(p->m)); | |||
| free(p); | |||
| } | |||
| @@ -0,0 +1,121 @@ | |||
| /* | |||
| opensl_io.c: | |||
| Android OpenSL input/output module header | |||
| Copyright (c) 2012, Victor Lazzarini | |||
| All rights reserved. | |||
| Redistribution and use in source and binary forms, with or without | |||
| modification, are permitted provided that the following conditions are met: | |||
| * Redistributions of source code must retain the above copyright | |||
| notice, this list of conditions and the following disclaimer. | |||
| * Redistributions in binary form must reproduce the above copyright | |||
| notice, this list of conditions and the following disclaimer in the | |||
| documentation and/or other materials provided with the distribution. | |||
| * Neither the name of the <organization> nor the | |||
| names of its contributors may be used to endorse or promote products | |||
| derived from this software without specific prior written permission. | |||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY | |||
| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| */ | |||
| #ifndef OPENSL_IO | |||
| #define OPENSL_IO | |||
| #include <SLES/OpenSLES.h> | |||
| #include <SLES/OpenSLES_Android.h> | |||
| #include <pthread.h> | |||
| #include <stdlib.h> | |||
| typedef struct threadLock_{ | |||
| pthread_mutex_t m; | |||
| pthread_cond_t c; | |||
| unsigned char s; | |||
| } threadLock; | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| typedef struct opensl_stream { | |||
| // engine interfaces | |||
| SLObjectItf engineObject; | |||
| SLEngineItf engineEngine; | |||
| // output mix interfaces | |||
| SLObjectItf outputMixObject; | |||
| // buffer queue player interfaces | |||
| SLObjectItf bqPlayerObject; | |||
| SLPlayItf bqPlayerPlay; | |||
| SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue; | |||
| SLEffectSendItf bqPlayerEffectSend; | |||
| // recorder interfaces | |||
| SLObjectItf recorderObject; | |||
| SLRecordItf recorderRecord; | |||
| SLAndroidSimpleBufferQueueItf recorderBufferQueue; | |||
| // buffer indexes | |||
| int currentInputIndex; | |||
| int currentOutputIndex; | |||
| // current buffer half (0, 1) | |||
| int currentOutputBuffer; | |||
| int currentInputBuffer; | |||
| // buffers | |||
| short *outputBuffer[2]; | |||
| short *inputBuffer[2]; | |||
| // size of buffers | |||
| int outBufSamples; | |||
| int inBufSamples; | |||
| // locks | |||
| void* inlock; | |||
| void* outlock; | |||
| double time; | |||
| int inchannels; | |||
| int outchannels; | |||
| int sr; | |||
| } OPENSL_STREAM; | |||
| /* | |||
| Open the audio device with a given sampling rate (sr), input and output channels and IO buffer size | |||
| in frames. Returns a handle to the OpenSL stream | |||
| */ | |||
| OPENSL_STREAM* android_OpenAudioDevice(int sr, int inchannels, int outchannels, int bufferframes); | |||
| /* | |||
| Close the audio device | |||
| */ | |||
| void android_CloseAudioDevice(OPENSL_STREAM *p); | |||
| /* | |||
| Read a buffer from the OpenSL stream *p, of size samples. Returns the number of samples read. | |||
| */ | |||
| int android_AudioIn(OPENSL_STREAM *p, float *buffer,int size); | |||
| /* | |||
| Write a buffer to the OpenSL stream *p, of size samples. Returns the number of samples written. | |||
| */ | |||
| int android_AudioOut(OPENSL_STREAM *p, float *buffer,int size); | |||
| /* | |||
| Get the current IO block time in seconds | |||
| */ | |||
| double android_GetTimestamp(OPENSL_STREAM *p); | |||
| #ifdef __cplusplus | |||
| }; | |||
| #endif | |||
| #endif // #ifndef OPENSL_IO | |||
| @@ -45,7 +45,9 @@ | |||
| #define PORT_NUM 2048 | |||
| #endif | |||
| #ifndef PORT_NUM_MAX | |||
| #define PORT_NUM_MAX 4096 // The "max" value for ports used in connection manager, although port number in graph manager is dynamic | |||
| #endif | |||
| #define DRIVER_PORT_NUM 256 | |||
| @@ -33,6 +33,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| #include "control.h" | |||
| #include "JackConstants.h" | |||
| #include "JackPlatformPlug.h" | |||
| #ifdef __ANDROID__ | |||
| #include "JackControlAPIAndroid.h" | |||
| #endif | |||
| #if defined(JACK_DBUS) && defined(__linux__) | |||
| #include <dbus/dbus.h> | |||
| @@ -192,6 +195,25 @@ static void usage(FILE* file, jackctl_server_t *server) | |||
| } | |||
| } | |||
| #ifdef __ANDROID__ | |||
| static void jackctl_server_switch_master_dummy(jackctl_server_t * server_ctl, char * master_driver_name) | |||
| { | |||
| static bool is_dummy_driver = false; | |||
| if(!strcmp(master_driver_name, "dummy")) { | |||
| return; | |||
| } | |||
| jackctl_driver_t * driver_ctr; | |||
| if(is_dummy_driver) { | |||
| is_dummy_driver = false; | |||
| driver_ctr = jackctl_server_get_driver(server_ctl, master_driver_name); | |||
| } else { | |||
| is_dummy_driver = true; | |||
| driver_ctr = jackctl_server_get_driver(server_ctl, "dummy"); | |||
| } | |||
| jackctl_server_switch_master(server_ctl, driver_ctr); | |||
| } | |||
| #endif | |||
| // Prototype to be found in libjackserver | |||
| extern "C" void silent_jack_error_callback(const char *desc); | |||
| @@ -556,7 +578,19 @@ int main(int argc, char** argv) | |||
| return_value = 0; | |||
| // Waits for signal | |||
| #ifdef __ANDROID__ | |||
| //reserve SIGUSR2 signal for switching master driver | |||
| while(1) { | |||
| int signal = jackctl_wait_signals_and_return(sigmask); | |||
| if (signal == SIGUSR2) { | |||
| jackctl_server_switch_master_dummy(server_ctl, master_driver_name); | |||
| } else { | |||
| break; | |||
| } | |||
| } | |||
| #else | |||
| jackctl_wait_signals(sigmask); | |||
| #endif | |||
| stop_server: | |||
| if (!jackctl_server_stop(server_ctl)) { | |||
| @@ -369,7 +369,7 @@ typedef int (*JackSampleRateCallback)(jack_nframes_t nframes, void *arg); | |||
| * @param register non-zero if the port is being registered, | |||
| * zero if the port is being unregistered | |||
| */ | |||
| typedef void (*JackPortRegistrationCallback)(jack_port_id_t port, int register, void *arg); | |||
| typedef void (*JackPortRegistrationCallback)(jack_port_id_t port, int /* register */, void *arg); | |||
| /** | |||
| * Prototype for the client supplied function that is called | |||
| @@ -380,7 +380,7 @@ typedef void (*JackPortRegistrationCallback)(jack_port_id_t port, int register, | |||
| * zero if the client is being unregistered | |||
| * @param arg pointer to a client supplied structure | |||
| */ | |||
| typedef void (*JackClientRegistrationCallback)(const char* name, int register, void *arg); | |||
| typedef void (*JackClientRegistrationCallback)(const char* name, int /* register */, void *arg); | |||
| /** | |||
| * Prototype for the client supplied function that is called | |||
| @@ -79,6 +79,19 @@ extern "C" | |||
| typedef char shm_name_t[SHM_NAME_MAX]; | |||
| typedef shm_name_t jack_shm_id_t; | |||
| #elif __ANDROID__ | |||
| #ifndef NAME_MAX | |||
| #define NAME_MAX 255 | |||
| #endif | |||
| #ifndef SHM_NAME_MAX | |||
| #define SHM_NAME_MAX NAME_MAX | |||
| #endif | |||
| typedef char shm_name_t[SHM_NAME_MAX]; | |||
| typedef shm_name_t jack_shm_id_t; | |||
| typedef int jack_shm_fd_t; | |||
| #else | |||
| /* System V SHM */ | |||
| typedef int jack_shm_id_t; | |||
| @@ -88,7 +101,8 @@ extern "C" | |||
| typedef enum { | |||
| shm_POSIX = 1, /* POSIX shared memory */ | |||
| shm_SYSV = 2, /* System V shared memory */ | |||
| shm_WIN32 = 3 /* Windows 32 shared memory */ | |||
| shm_WIN32 = 3, /* Windows 32 shared memory */ | |||
| shm_ANDROID = 4 /* Android shared memory */ | |||
| } jack_shmtype_t; | |||
| typedef int16_t jack_shm_registry_index_t; | |||
| @@ -135,6 +149,9 @@ extern "C" | |||
| jack_shmsize_t size; /* for POSIX unattach */ | |||
| jack_shm_id_t id; /* API specific, see above */ | |||
| #ifdef __ANDROID__ | |||
| jack_shm_fd_t fd; | |||
| #endif | |||
| } | |||
| jack_shm_registry_t; | |||
| @@ -153,6 +170,9 @@ extern "C" | |||
| struct _jack_shm_info { | |||
| jack_shm_registry_index_t index; /* offset into the registry */ | |||
| uint32_t size; | |||
| #ifdef __ANDROID__ | |||
| jack_shm_fd_t fd; | |||
| #endif | |||
| union { | |||
| void *attached_at; /* address where attached */ | |||
| char ptr_size[8]; | |||
| @@ -99,6 +99,9 @@ alsa_format_t formats[] = { | |||
| { SND_PCM_FORMAT_S24_3LE, 3, sample_move_d24_sS, sample_move_dS_s24, "24bit - real" }, | |||
| { SND_PCM_FORMAT_S24, 4, sample_move_d24_sS, sample_move_dS_s24, "24bit" }, | |||
| { SND_PCM_FORMAT_S16, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit" } | |||
| #ifdef __ANDROID__ | |||
| ,{ SND_PCM_FORMAT_S16_LE, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit little-endian" } | |||
| #endif | |||
| }; | |||
| #define NUMFORMATS (sizeof(formats)/sizeof(formats[0])) | |||
| int format=0; | |||
| @@ -127,6 +130,11 @@ static int xrun_recovery(snd_pcm_t *handle, int err) { | |||
| static int set_hwformat( snd_pcm_t *handle, snd_pcm_hw_params_t *params ) | |||
| { | |||
| #ifdef __ANDROID__ | |||
| format = 5; | |||
| snd_pcm_hw_params_set_format(handle, params, formats[format].format_id); | |||
| return 0; | |||
| #else | |||
| int i; | |||
| int err; | |||
| @@ -140,6 +148,7 @@ static int set_hwformat( snd_pcm_t *handle, snd_pcm_hw_params_t *params ) | |||
| } | |||
| return err; | |||
| #endif | |||
| } | |||
| static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access, int rate, int channels, int period, int nperiods ) { | |||
| @@ -99,6 +99,9 @@ alsa_format_t formats[] = { | |||
| { SND_PCM_FORMAT_S24_3LE, 3, sample_move_d24_sS, sample_move_dS_s24, "24bit - real" }, | |||
| { SND_PCM_FORMAT_S24, 4, sample_move_d24_sS, sample_move_dS_s24, "24bit" }, | |||
| { SND_PCM_FORMAT_S16, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit" } | |||
| #ifdef __ANDROID__ | |||
| ,{ SND_PCM_FORMAT_S16_LE, 2, sample_move_d16_sS, sample_move_dS_s16, "16bit little-endian" } | |||
| #endif | |||
| }; | |||
| #define NUMFORMATS (sizeof(formats)/sizeof(formats[0])) | |||
| int format=0; | |||
| @@ -127,6 +130,11 @@ static int xrun_recovery(snd_pcm_t *handle, int err) { | |||
| static int set_hwformat( snd_pcm_t *handle, snd_pcm_hw_params_t *params ) | |||
| { | |||
| #ifdef __ANDROID__ | |||
| format = 5; | |||
| snd_pcm_hw_params_set_format(handle, params, formats[format].format_id); | |||
| return 0; | |||
| #else | |||
| int i; | |||
| int err; | |||
| @@ -140,6 +148,7 @@ static int set_hwformat( snd_pcm_t *handle, snd_pcm_hw_params_t *params ) | |||
| } | |||
| return err; | |||
| #endif | |||
| } | |||
| static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access, int rate, int channels, int period, int nperiods ) { | |||
| @@ -635,7 +635,7 @@ main(int argc, char **argv) | |||
| timeout = 5; | |||
| for (;;) { | |||
| char c = getopt_long(argc, argv, option_string, long_options, | |||
| signed char c = getopt_long(argc, argv, option_string, long_options, | |||
| &long_index); | |||
| switch (c) { | |||
| case 'h': | |||
| @@ -24,11 +24,16 @@ | |||
| #include <signal.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #ifdef HAVE_READLINE | |||
| #include <readline/readline.h> | |||
| #include <readline/history.h> | |||
| #endif | |||
| #include <jack/jack.h> | |||
| #include <jack/transport.h> | |||
| #ifndef HAVE_READLINE | |||
| #define whitespace(c) (((c) == ' ') || ((c) == '\t')) | |||
| #endif | |||
| char *package; /* program name */ | |||
| int done = 0; | |||
| @@ -384,6 +389,7 @@ static char *command_generator (const char *text, int state) | |||
| static void command_loop() | |||
| { | |||
| #ifdef HAVE_READLINE | |||
| char *line, *cmd; | |||
| char prompt[32]; | |||
| @@ -394,10 +400,15 @@ static void command_loop() | |||
| /* Define a custom completion function. */ | |||
| rl_completion_entry_function = command_generator; | |||
| #else | |||
| char line[64] = {0,}; | |||
| char *cmd = NULL; | |||
| #endif | |||
| /* Read and execute commands until the user quits. */ | |||
| while (!done) { | |||
| #ifdef HAVE_READLINE | |||
| line = readline(prompt); | |||
| if (line == NULL) { /* EOF? */ | |||
| @@ -405,6 +416,11 @@ static void command_loop() | |||
| done = 1; | |||
| break; | |||
| } | |||
| #else | |||
| printf("%s> ", package); | |||
| fgets(line, sizeof(line), stdin); | |||
| line[strlen(line)-1] = '\0'; | |||
| #endif | |||
| /* Remove leading and trailing whitespace from the line. */ | |||
| cmd = stripwhite(line); | |||
| @@ -412,11 +428,15 @@ static void command_loop() | |||
| /* If anything left, add to history and execute it. */ | |||
| if (*cmd) | |||
| { | |||
| #ifdef HAVE_READLINE | |||
| add_history(cmd); | |||
| #endif | |||
| execute_command(cmd); | |||
| } | |||
| #ifdef HAVE_READLINE | |||
| free(line); /* realine() called malloc() */ | |||
| #endif | |||
| } | |||
| } | |||
| @@ -39,7 +39,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| #include "JackPort.h" | |||
| #include "JackGraphManager.h" | |||
| #include "JackLockedEngine.h" | |||
| #ifdef __ANDROID__ | |||
| #include "JackAndroidThread.h" | |||
| #else | |||
| #include "JackPosixThread.h" | |||
| #endif | |||
| #include "JackCompilerDeps.h" | |||
| #include "JackServerGlobals.h" | |||
| @@ -469,7 +473,11 @@ int JackAlsaDriver::is_realtime() const | |||
| int JackAlsaDriver::create_thread(pthread_t *thread, int priority, int realtime, void *(*start_routine)(void*), void *arg) | |||
| { | |||
| #ifdef __ANDROID__ | |||
| return JackAndroidThread::StartImp(thread, priority, realtime, start_routine, arg); | |||
| #else | |||
| return JackPosixThread::StartImp(thread, priority, realtime, start_routine, arg); | |||
| #endif | |||
| } | |||
| jack_port_id_t JackAlsaDriver::port_register(const char *port_name, const char *port_type, unsigned long flags, unsigned long buffer_size) | |||
| @@ -739,7 +747,11 @@ SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () | |||
| desc = jack_driver_descriptor_construct("alsa", JackDriverMaster, "Linux ALSA API based audio backend", &filler); | |||
| strcpy(value.str, "hw:0"); | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, enum_alsa_devices(), "ALSA device name", NULL); | |||
| #ifdef __ANDROID__ | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "ALSA device name", NULL); | |||
| #else | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, enum_alsa_devices, "ALSA device name", NULL); | |||
| #endif | |||
| strcpy(value.str, "none"); | |||
| jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamString, &value, NULL, "Provide capture ports. Optionally set device", NULL); | |||
| @@ -368,7 +368,7 @@ alsa_driver_configure_stream (alsa_driver_t *driver, char *device_name, | |||
| snd_pcm_format_t format; | |||
| int swapped; | |||
| } formats[] = { | |||
| {"32bit float little-endian", SND_PCM_FORMAT_FLOAT_LE}, | |||
| {"32bit float little-endian", SND_PCM_FORMAT_FLOAT_LE, IS_LE}, | |||
| {"32bit integer little-endian", SND_PCM_FORMAT_S32_LE, IS_LE}, | |||
| {"32bit integer big-endian", SND_PCM_FORMAT_S32_BE, IS_BE}, | |||
| {"24bit little-endian", SND_PCM_FORMAT_S24_3LE, IS_LE}, | |||
| @@ -914,7 +914,7 @@ alsa_driver_get_channel_addresses (alsa_driver_t *driver, | |||
| snd_pcm_uframes_t *capture_offset, | |||
| snd_pcm_uframes_t *playback_offset) | |||
| { | |||
| unsigned long err; | |||
| int err; | |||
| channel_t chn; | |||
| if (capture_avail) { | |||
| @@ -1320,7 +1320,11 @@ alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float | |||
| driver->poll_late++; | |||
| } | |||
| #ifdef __ANDROID__ | |||
| poll_result = poll (driver->pfd, nfds, -1); //fix for sleep issue | |||
| #else | |||
| poll_result = poll (driver->pfd, nfds, driver->poll_timeout); | |||
| #endif | |||
| if (poll_result < 0) { | |||
| if (errno == EINTR) { | |||
| @@ -2034,6 +2038,13 @@ alsa_driver_new (char *name, char *playback_alsa_device, | |||
| SND_PCM_NONBLOCK) < 0) { | |||
| switch (errno) { | |||
| case EBUSY: | |||
| #ifdef __ANDROID__ | |||
| jack_error ("\n\nATTENTION: The playback device \"%s\" is " | |||
| "already in use. Please stop the" | |||
| " application using it and " | |||
| "run JACK again", | |||
| playback_alsa_device); | |||
| #else | |||
| current_apps = discover_alsa_using_apps (); | |||
| if (current_apps) { | |||
| jack_error ("\n\nATTENTION: The playback device \"%s\" is " | |||
| @@ -2051,6 +2062,7 @@ alsa_driver_new (char *name, char *playback_alsa_device, | |||
| "run JACK again", | |||
| playback_alsa_device); | |||
| } | |||
| #endif | |||
| alsa_driver_delete (driver); | |||
| return NULL; | |||
| @@ -2078,6 +2090,13 @@ alsa_driver_new (char *name, char *playback_alsa_device, | |||
| SND_PCM_NONBLOCK) < 0) { | |||
| switch (errno) { | |||
| case EBUSY: | |||
| #ifdef __ANDROID__ | |||
| jack_error ("\n\nATTENTION: The capture (recording) device \"%s\" is " | |||
| "already in use. Please stop the" | |||
| " application using it and " | |||
| "run JACK again", | |||
| capture_alsa_device); | |||
| #else | |||
| current_apps = discover_alsa_using_apps (); | |||
| if (current_apps) { | |||
| jack_error ("\n\nATTENTION: The capture device \"%s\" is " | |||
| @@ -2095,6 +2114,7 @@ alsa_driver_new (char *name, char *playback_alsa_device, | |||
| "run JACK again", | |||
| capture_alsa_device); | |||
| } | |||
| #endif | |||
| alsa_driver_delete (driver); | |||
| return NULL; | |||
| break; | |||
| @@ -37,6 +37,8 @@ | |||
| #include "midi_unpack.h" | |||
| #include "JackError.h" | |||
| extern int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *req, struct timespec *rem); | |||
| enum { | |||
| NANOSLEEP_RESOLUTION = 7000 | |||
| }; | |||
| @@ -808,8 +810,9 @@ void jack_process(midi_stream_t *str, jack_nframes_t nframes) | |||
| str->jack.ports[w] = port; | |||
| ++w; | |||
| } | |||
| if (str->jack.nports != w) | |||
| if (str->jack.nports != w) { | |||
| debug_log("jack_%s: nports %d -> %d", str->name, str->jack.nports, w); | |||
| } | |||
| str->jack.nports = w; | |||
| jack_add_ports(str); // it makes no sense to add them earlier since they have no data yet | |||
| @@ -910,11 +913,13 @@ void *midi_thread(void *arg) | |||
| str->midi.ports[wp] = port; | |||
| ++wp; | |||
| } | |||
| if (str->midi.nports != wp) | |||
| if (str->midi.nports != wp) { | |||
| debug_log("midi_%s: nports %d -> %d", str->name, str->midi.nports, wp); | |||
| } | |||
| str->midi.nports = wp; | |||
| if (npfds != w) | |||
| if (npfds != w) { | |||
| debug_log("midi_%s: npfds %d -> %d", str->name, npfds, w); | |||
| } | |||
| npfds = w; | |||
| /* | |||
| @@ -1054,8 +1059,9 @@ int do_midi_input(process_midi_t *proc) | |||
| jack_ringbuffer_get_write_vector(port->base.data_ring, vec); | |||
| if (jack_ringbuffer_write_space(port->base.event_ring) < sizeof(event_head_t) || vec[0].len < 1) { | |||
| port->overruns++; | |||
| if (port->base.npfds) | |||
| if (port->base.npfds) { | |||
| debug_log("midi_in: internal overflow on %s", port->base.name); | |||
| } | |||
| // remove from poll to prevent busy-looping | |||
| port->base.npfds = 0; | |||
| return 1; | |||
| @@ -1106,8 +1112,9 @@ void do_jack_output(process_jack_t *proc) | |||
| output_port_t *port = (output_port_t*) proc->port; | |||
| int nevents = jack_midi_get_event_count(proc->buffer); | |||
| int i; | |||
| if (nevents) | |||
| if (nevents) { | |||
| debug_log("jack_out: %d events in %s", nevents, port->base.name); | |||
| } | |||
| for (i=0; i<nevents; ++i) { | |||
| jack_midi_event_t event; | |||
| event_head_t hdr; | |||
| @@ -1146,12 +1153,14 @@ int do_midi_output(process_midi_t *proc) | |||
| port->next_event.time = 0; | |||
| port->next_event.size = 0; | |||
| break; | |||
| } else | |||
| } else { | |||
| debug_log("midi_out: at %ld got %d bytes for %ld", (long)proc->cur_time, (int)port->next_event.size, (long)port->next_event.time); | |||
| } | |||
| } | |||
| if (port->todo) | |||
| if (port->todo) { | |||
| debug_log("midi_out: todo = %d at %ld", (int)port->todo, (long)proc->cur_time); | |||
| } | |||
| // calc next wakeup time | |||
| if (!port->todo && port->next_event.time && port->next_event.time < proc->next_time) { | |||
| @@ -1193,8 +1202,9 @@ int do_midi_output(process_midi_t *proc) | |||
| if (!port->todo) { | |||
| int i; | |||
| if (worked) | |||
| if (worked) { | |||
| debug_log("midi_out: relaxing on %s", port->base.name); | |||
| } | |||
| for (i=0; i<port->base.npfds; ++i) | |||
| proc->wpfds[i].events &= ~POLLOUT; | |||
| } else { | |||
| @@ -438,8 +438,9 @@ void port_setdead(port_hash_t hash, snd_seq_addr_t addr) | |||
| port_t *port = port_get(hash, addr); | |||
| if (port) | |||
| port->is_dead = 1; // see jack_process | |||
| else | |||
| else { | |||
| debug_log("port_setdead: not found (%d:%d)", addr.client, addr.port); | |||
| } | |||
| } | |||
| static | |||
| @@ -728,7 +729,7 @@ void do_jack_input(alsa_seqmidi_t *self, port_t *port, struct process_info *info | |||
| alsa_midi_event_t ev; | |||
| while (jack_ringbuffer_read(port->early_events, (char*)&ev, sizeof(ev))) { | |||
| jack_midi_data_t* buf; | |||
| jack_nframes_t time = ev.time - info->period_start; | |||
| int64_t time = ev.time - info->period_start; | |||
| if (time < 0) | |||
| time = 0; | |||
| else if (time >= info->nframes) | |||
| @@ -206,10 +206,12 @@ hammerfall_release (jack_hardware_t *hw) | |||
| return; | |||
| } | |||
| #ifndef __ANDROID__ | |||
| if (h->monitor_thread) { | |||
| pthread_cancel (h->monitor_thread); | |||
| pthread_join (h->monitor_thread, &status); | |||
| } | |||
| #endif | |||
| free (h); | |||
| } | |||