From 252df2cc9563522e9aef02b0b13010421b60e5fe Mon Sep 17 00:00:00 2001 From: hooby3dfx Date: Mon, 13 Jan 2014 12:12:26 -0500 Subject: [PATCH 01/19] Holy Seaman, batman! Seaman will load :) --- core/hw/maple/maple_cfg.cpp | 2 +- core/hw/maple/maple_devs.cpp | 85 +++++++++++++++++++++++++++++++++++- core/hw/maple/maple_devs.h | 1 + 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/core/hw/maple/maple_cfg.cpp b/core/hw/maple/maple_cfg.cpp index 16e5a63fe..8ed2b09cc 100644 --- a/core/hw/maple/maple_cfg.cpp +++ b/core/hw/maple/maple_cfg.cpp @@ -72,7 +72,7 @@ void mcfg_CreateDevices() #ifdef HAS_VMU mcfg_Create(MDT_SegaVMU,0,0); - mcfg_Create(MDT_SegaVMU,0,1); + mcfg_Create(MDT_Microphone,0,1); #endif } diff --git a/core/hw/maple/maple_devs.cpp b/core/hw/maple/maple_devs.cpp index c352db493..aa684a304 100755 --- a/core/hw/maple/maple_devs.cpp +++ b/core/hw/maple/maple_devs.cpp @@ -651,6 +651,86 @@ struct maple_sega_vmu: maple_base }; #endif +struct maple_microphone: maple_base +{ + virtual u32 dma(u32 cmd) + { + //printf("maple_microphone::dma Called 0x%X;Command %d\n",device_instance->port,Command); + switch (cmd) + { + case MDC_DeviceRequest: + //caps + //4 + w32(MFID_4_Mic); + + //struct data + //3*4 + w32( 0xfe060f00); + w32( 0); + w32( 0); + + //1 area code + w8(0xFF); + + //1 direction + w8(0); + + //30 + wstr(maple_sega_mic_name,30); + + //60 + wstr(maple_sega_brand,60); + + //2 + w16(0x01AE); + + //2 + w16(0x01F4); + + return MDRS_DeviceStatus; + + //controller condition + case MDCF_GetCondition: + { + //PlainJoystickState pjs; + //config->GetInput(&pjs); + //caps + //4 + w32(MFID_4_Mic); + + //state data + //2 key code + //w16(pjs.kcode); + + //triggers + //1 R + //w8(pjs.trigger[PJTI_R]); + //1 L + //w8(pjs.trigger[PJTI_L]); + + //joyx + //1 + //w8(pjs.joy[PJAI_X1]); + //joyy + //1 + //w8(pjs.joy[PJAI_Y1]); + + //not used + //1 + w8(0x80); + //1 + w8(0x80); + } + + return MDRS_DataTransfer; + + default: + printf("UNKOWN MAPLE COMMAND %d\n",cmd); + return MDRE_UnknownFunction; + } + } +}; + maple_device* maple_Create(MapleDeviceType type) { maple_device* rv=0; @@ -659,6 +739,9 @@ maple_device* maple_Create(MapleDeviceType type) case MDT_SegaController: rv=new maple_sega_controller(); break; + case MDT_Microphone: + rv=new maple_microphone(); + break; #ifdef HAS_VMU case MDT_SegaVMU: rv = new maple_sega_vmu(); @@ -670,4 +753,4 @@ maple_device* maple_Create(MapleDeviceType type) } return rv; -} \ No newline at end of file +} diff --git a/core/hw/maple/maple_devs.h b/core/hw/maple/maple_devs.h index 0c9980dc0..2793e039f 100644 --- a/core/hw/maple/maple_devs.h +++ b/core/hw/maple/maple_devs.h @@ -5,6 +5,7 @@ enum MapleDeviceType { MDT_SegaController, MDT_SegaVMU, + MDT_Microphone, MDT_Count }; From 1cb31dd932d5c2f8e46a4fbafcf8de41818092de Mon Sep 17 00:00:00 2001 From: hooby3dfx Date: Mon, 13 Jan 2014 16:30:42 -0500 Subject: [PATCH 02/19] logging changes trying to hone in on commands going in and out --- core/hw/maple/maple_devs.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/core/hw/maple/maple_devs.cpp b/core/hw/maple/maple_devs.cpp index aa684a304..706877402 100755 --- a/core/hw/maple/maple_devs.cpp +++ b/core/hw/maple/maple_devs.cpp @@ -225,7 +225,7 @@ struct maple_sega_controller: maple_base return MDRS_DataTransfer; default: - printf("UNKOWN MAPLE COMMAND %d\n",cmd); + //printf("UNKOWN MAPLE COMMAND %d\n",cmd); return MDRE_UnknownFunction; } } @@ -644,7 +644,7 @@ struct maple_sega_vmu: maple_base default: - printf("Unknown MAPLE COMMAND %d\n",cmd); + //printf("Unknown MAPLE COMMAND %d\n",cmd); return MDRE_UnknownCmd; } } @@ -655,7 +655,7 @@ struct maple_microphone: maple_base { virtual u32 dma(u32 cmd) { - //printf("maple_microphone::dma Called 0x%X;Command %d\n",device_instance->port,Command); + printf("maple_microphone::dma Called 0x%X;Command %d\n",this->maple_port,cmd); switch (cmd) { case MDC_DeviceRequest: @@ -723,9 +723,13 @@ struct maple_microphone: maple_base } return MDRS_DataTransfer; + + case MDC_DeviceReset: + + return MDRS_DeviceReply; default: - printf("UNKOWN MAPLE COMMAND %d\n",cmd); + printf("maple_microphone::dma UNHANDLED MAPLE COMMAND %d\n",cmd); return MDRE_UnknownFunction; } } From 8284f55b680cf6f802fb67561ce5e08a1c4ba474 Mon Sep 17 00:00:00 2001 From: hooby3dfx Date: Mon, 13 Jan 2014 17:02:22 -0500 Subject: [PATCH 03/19] initial dox --- docs/microphone support notes.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 docs/microphone support notes.txt diff --git a/docs/microphone support notes.txt b/docs/microphone support notes.txt new file mode 100644 index 000000000..93ad45054 --- /dev/null +++ b/docs/microphone support notes.txt @@ -0,0 +1,12 @@ +1/13/2014 hooby3dfx + +general info links from bluecrab: http://dreamcast-talk.com/forum/viewtopic.php?t=2921&f=5 +kallistios driver (could use for test app): http://cadcdev.sourceforge.net/docs/kos-2.0.0/sip_8h.html +maplebus: https://web.archive.org/web/20101117090620/http://mc.pp.se/dc/maplebus.html + +plan: +-figure out the mic commands that seaman is looking for and implement them +-create mic test app (consult bluecrab) +-figure out how the game/dc requests the audio (or how the mic just streams)... +-for poc just create some kind of global way to pass the audio data from android mic interface directly to the maple_base instance +-cleanup \ No newline at end of file From babaf41482d42f6c834f5203206a2b3e2aa06a54 Mon Sep 17 00:00:00 2001 From: Bryan Barnes Date: Tue, 14 Jan 2014 00:38:59 -0500 Subject: [PATCH 04/19] mic device figured out? i have satisfied seaman. its just constantly polling for data. next step: pipe in some audio! --- core/hw/maple/maple_devs.cpp | 71 +++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/core/hw/maple/maple_devs.cpp b/core/hw/maple/maple_devs.cpp index 706877402..30ed2c03f 100755 --- a/core/hw/maple/maple_devs.cpp +++ b/core/hw/maple/maple_devs.cpp @@ -4,6 +4,7 @@ #include "maple_devs.h" #include "maple_cfg.h" #include +#include #include "deps/zlib/zlib.h" @@ -18,6 +19,7 @@ const char* maple_sega_mic_name = "MicDevice for Dreameye"; const char* maple_sega_brand = "Produced By or Under License From SEGA ENTERPRISES,LTD."; #define HAS_VMU +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "maple_devs", __VA_ARGS__) enum MapleFunctionID { @@ -655,10 +657,13 @@ struct maple_microphone: maple_base { virtual u32 dma(u32 cmd) { - printf("maple_microphone::dma Called 0x%X;Command %d\n",this->maple_port,cmd); + //printf("maple_microphone::dma Called 0x%X;Command %d\n",this->maple_port,cmd); + //LOGD("maple_microphone::dma Called 0x%X;Command %d\n",this->maple_port,cmd); + switch (cmd) { case MDC_DeviceRequest: + LOGD("maple_microphone::dma MDC_DeviceRequest"); //caps //4 w32(MFID_4_Mic); @@ -722,14 +727,68 @@ struct maple_microphone: maple_base w8(0x80); } - return MDRS_DataTransfer; - + return MDRS_DataTransfer; + case MDC_DeviceReset: - - return MDRS_DeviceReply; + //uhhh do nothing? + LOGD("maple_microphone::dma MDC_DeviceReset"); + return MDRS_DeviceReply; + + case MDCF_MICControl: + { + //MONEY + u32 function=r32(); + LOGD("maple_microphone::dma MDCF_MICControl function (1st word) %#010x\n", function); + LOGD("maple_microphone::dma MDCF_MICControl words: %d\n", dma_count_in); + + switch(function) + { + case MFID_4_Mic: + { + //MAGIC HERE + //http://dcemulation.org/phpBB/viewtopic.php?f=34&t=69600 + // <3 <3 BlueCrab <3 <3 + /* + 2nd word What it does: + 0x0000??03 Sets the amplifier gain, ?? can be from 00 to 1F + 0x0f = default + 0x00008002 Enables recording + 0x00000001 Returns sampled data while recording is enabled + While not enabled, returns status of the mic. + 0x00000002 Disables recording + * + */ + u32 subcommand=r32(); + LOGD("maple_microphone::dma MDCF_MICControl subcommand (2nd word) %#010x\n", subcommand); + //u32 cmd = (number >> (8*n)) & 0xff + u32 cmd = subcommand & 0xFF; + + LOGD("maple_microphone::dma MDCF_MICControl (3rd word) %#010x\n", r32()); + LOGD("maple_microphone::dma MDCF_MICControl (4th word) %#010x\n", r32()); + switch(cmd) + { + case 0x01: + LOGD("maple_microphone::dma MDCF_MICControl someone wants some data!"); + return MDRS_DataTransfer; + break; + case 0x02: + LOGD("maple_microphone::dma MDCF_MICControl toggle recording!"); + return MDRS_DeviceReply; + break; + case 0x03: + return MDRS_DeviceReply; + break; + default: + break; + } + } + default: + break; + } + } default: - printf("maple_microphone::dma UNHANDLED MAPLE COMMAND %d\n",cmd); + LOGD("maple_microphone::dma UNHANDLED MAPLE COMMAND %d\n",cmd); return MDRE_UnknownFunction; } } From 18e5bd7c95e36ba1245ba79d5451e571b6789979 Mon Sep 17 00:00:00 2001 From: Bryan Barnes Date: Thu, 16 Jan 2014 01:36:04 -0500 Subject: [PATCH 05/19] almost working crashes - need to figure out jni thread crap --- core/hw/maple/maple_devs.cpp | 33 ++++-- core/hw/maple/maple_devs.h | 3 +- shell/android/AndroidManifest.xml | 2 + shell/android/jni/src/Android.cpp | 24 ++++ .../com/reicast/emulator/GL2JNIActivity.java | 7 ++ .../src/com/reicast/emulator/JNIdc.java | 2 + .../src/com/reicast/emulator/SipEmulator.java | 107 ++++++++++++++++++ 7 files changed, 166 insertions(+), 12 deletions(-) create mode 100644 shell/android/src/com/reicast/emulator/SipEmulator.java diff --git a/core/hw/maple/maple_devs.cpp b/core/hw/maple/maple_devs.cpp index 30ed2c03f..69d320bf3 100755 --- a/core/hw/maple/maple_devs.cpp +++ b/core/hw/maple/maple_devs.cpp @@ -5,6 +5,7 @@ #include "maple_cfg.h" #include #include +#include #include "deps/zlib/zlib.h" @@ -664,6 +665,8 @@ struct maple_microphone: maple_base { case MDC_DeviceRequest: LOGD("maple_microphone::dma MDC_DeviceRequest"); + //this was copied from the controller case with just the id and name replaced! + //caps //4 w32(MFID_4_Mic); @@ -694,9 +697,10 @@ struct maple_microphone: maple_base return MDRS_DeviceStatus; - //controller condition case MDCF_GetCondition: { + //this was copied from the controller case with just the id replaced! + //PlainJoystickState pjs; //config->GetInput(&pjs); //caps @@ -738,8 +742,8 @@ struct maple_microphone: maple_base { //MONEY u32 function=r32(); - LOGD("maple_microphone::dma MDCF_MICControl function (1st word) %#010x\n", function); - LOGD("maple_microphone::dma MDCF_MICControl words: %d\n", dma_count_in); + //LOGD("maple_microphone::dma MDCF_MICControl function (1st word) %#010x\n", function); + //LOGD("maple_microphone::dma MDCF_MICControl words: %d\n", dma_count_in); switch(function) { @@ -759,25 +763,32 @@ struct maple_microphone: maple_base * */ u32 subcommand=r32(); - LOGD("maple_microphone::dma MDCF_MICControl subcommand (2nd word) %#010x\n", subcommand); - //u32 cmd = (number >> (8*n)) & 0xff - u32 cmd = subcommand & 0xFF; + //LOGD("maple_microphone::dma MDCF_MICControl subcommand (2nd word) %#010x\n", subcommand); - LOGD("maple_microphone::dma MDCF_MICControl (3rd word) %#010x\n", r32()); - LOGD("maple_microphone::dma MDCF_MICControl (4th word) %#010x\n", r32()); + u32 cmd = subcommand & 0xFF; //just get last byte for now, deal with params later + + //LOGD("maple_microphone::dma MDCF_MICControl (3rd word) %#010x\n", r32()); + //LOGD("maple_microphone::dma MDCF_MICControl (4th word) %#010x\n", r32()); switch(cmd) { case 0x01: + { LOGD("maple_microphone::dma MDCF_MICControl someone wants some data!"); + //maximum size of a Maple Bus packet is 256 words (1024 bytes) + //maybe i should start with 512 (same as vmu) + u8* micdata=(u8*)malloc(512); + get_mic_data(micdata); //this is crashing (jni issue) + wptr(micdata, 512); + return MDRS_DataTransfer; - break; + } case 0x02: LOGD("maple_microphone::dma MDCF_MICControl toggle recording!"); + //this is where i should start recording... + return MDRS_DeviceReply; - break; case 0x03: return MDRS_DeviceReply; - break; default: break; } diff --git a/core/hw/maple/maple_devs.h b/core/hw/maple/maple_devs.h index 2793e039f..9a7daadd7 100644 --- a/core/hw/maple/maple_devs.h +++ b/core/hw/maple/maple_devs.h @@ -28,4 +28,5 @@ struct maple_device virtual u32 Dma(u32 Command,u32* buffer_in,u32 buffer_in_len,u32* buffer_out,u32& buffer_out_len)=0; }; -maple_device* maple_Create(MapleDeviceType type); \ No newline at end of file +maple_device* maple_Create(MapleDeviceType type); +void get_mic_data(u8* buffer); diff --git a/shell/android/AndroidManifest.xml b/shell/android/AndroidManifest.xml index a92509b6a..cdcac06e2 100644 --- a/shell/android/AndroidManifest.xml +++ b/shell/android/AndroidManifest.xml @@ -10,9 +10,11 @@ + + GetMethodID(env->GetObjectClass(sipemu),"getData","()[B"); + +} + JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_stop(JNIEnv *env,jobject obj) { dc_term(); @@ -330,3 +345,12 @@ bool os_IsAudioBuffered() { return jenv->CallIntMethod(track,writemid,jsamples,-1)==0; } + +void get_mic_data(u8* buffer) +{ + LOGD("get_mic_data called"); + jbyteArray jdata = (jbyteArray)jenv->CallObjectMethod(sipemu,getmicdata); + LOGD("CallObjectMethod happened"); + jenv->GetByteArrayRegion(jdata, 0, 512, (jbyte*)buffer); + LOGD("GetByteArrayRegion happened"); +} diff --git a/shell/android/src/com/reicast/emulator/GL2JNIActivity.java b/shell/android/src/com/reicast/emulator/GL2JNIActivity.java index 88c5e38e9..64931cff0 100644 --- a/shell/android/src/com/reicast/emulator/GL2JNIActivity.java +++ b/shell/android/src/com/reicast/emulator/GL2JNIActivity.java @@ -325,6 +325,13 @@ public class GL2JNIActivity extends Activity { Toast.makeText(getApplicationContext(), "Press the back button for a menu", Toast.LENGTH_SHORT).show(); + + + //totally hijacking this to setup mic + SipEmulator sip = new SipEmulator(); + sip.startRecording(); + JNIdc.setupMic(sip); + } private void runCompatibilityMode() { diff --git a/shell/android/src/com/reicast/emulator/JNIdc.java b/shell/android/src/com/reicast/emulator/JNIdc.java index c29c67117..b1dc12fbb 100644 --- a/shell/android/src/com/reicast/emulator/JNIdc.java +++ b/shell/android/src/com/reicast/emulator/JNIdc.java @@ -22,6 +22,8 @@ public class JNIdc //public static native int play(short result[],int size); public static native void initControllers(boolean[] controllers); + + public static native void setupMic(Object sip); public static void show_osd() { JNIdc.vjoy(13, 1,0,0,0); diff --git a/shell/android/src/com/reicast/emulator/SipEmulator.java b/shell/android/src/com/reicast/emulator/SipEmulator.java new file mode 100644 index 000000000..ea6dcc2c6 --- /dev/null +++ b/shell/android/src/com/reicast/emulator/SipEmulator.java @@ -0,0 +1,107 @@ +package com.reicast.emulator; + +import java.util.LinkedList; + +import android.media.AudioFormat; +import android.media.AudioRecord; +import android.media.MediaRecorder; +import android.util.Log; + +public class SipEmulator extends Thread{ + + static final String TAG = "SipEmulator"; + + //one second of audio data in bytes + static final int BUFFER_SIZE = 22050; + //this needs to get set to the amount the mic normally sends per data request + //--->target 512! + static final int ONE_BLIP_SIZE = 512; + static final long TIME_TO_WAIT_BETWEEN_POLLS = 1000 / 44; //poll every ~23 ms + + private AudioRecord record; + private LinkedList bytesReadBuffer; + + private Thread recordThread; + private boolean continueRecording; + + /* + 16-bit PCM @ 11025 hz + == 176.4 kbit/s + == 22050 bytes/s + */ + + public SipEmulator(){ + + Log.d(TAG, "SipEmulator constructor called"); + + init(); + + + } + + private void init(){ + Log.d(TAG, "SipEmulator init called"); + + record = new AudioRecord( + MediaRecorder.AudioSource.MIC, + 11025, + AudioFormat.CHANNEL_IN_MONO, + AudioFormat.ENCODING_PCM_16BIT, + BUFFER_SIZE); + + bytesReadBuffer = new LinkedList(); + + } + + + public void startRecording(){ + if(continueRecording){ + return; + } + Log.d(TAG, "SipEmulator startRecording called"); + record.startRecording(); + continueRecording = true; + this.start(); + } + + public void stopRecording(){ + Log.d(TAG, "SipEmulator stopRecording called"); + record.stop(); + continueRecording = false; + } + + public byte[] getData(){ + //Log.d(TAG, "SipEmulator getData called"); + Log.d(TAG, "SipEmulator getData bytesReadBuffer size: "+bytesReadBuffer.size()); + return bytesReadBuffer.poll(); + } + + public void configSomething(int what, int setting){ + Log.d(TAG, "SipEmulator configSomething called"); + + } + + public void run() { + Log.d(TAG, "recordThread starting"); + //sleep to let some data come in + // try { + // Thread.sleep(TIME_TO_WAIT_BETWEEN_POLLS); + // } catch (InterruptedException e) { + // e.printStackTrace(); + // } + + while(continueRecording){ + byte[] freshData = new byte[ONE_BLIP_SIZE]; + int bytesRead = record.read(freshData, 0, ONE_BLIP_SIZE); + //Log.d(TAG, "recordThread recorded: "+bytesRead); + bytesReadBuffer.add(freshData); + + try { + Thread.sleep(TIME_TO_WAIT_BETWEEN_POLLS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + +} From b24e401e2f9bb55267ca18059ce8dd5440147a34 Mon Sep 17 00:00:00 2001 From: Bryan Barnes Date: Thu, 16 Jan 2014 02:05:39 -0500 Subject: [PATCH 06/19] oh snap gets further! jni local reference table overflow --- core/hw/maple/maple_devs.cpp | 11 +++++++---- shell/android/jni/src/Android.cpp | 5 ++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/core/hw/maple/maple_devs.cpp b/core/hw/maple/maple_devs.cpp index 69d320bf3..7bdc1575e 100755 --- a/core/hw/maple/maple_devs.cpp +++ b/core/hw/maple/maple_devs.cpp @@ -740,6 +740,7 @@ struct maple_microphone: maple_base case MDCF_MICControl: { + //LOGD("maple_microphone::dma handling MDCF_MICControl %d\n",cmd); //MONEY u32 function=r32(); //LOGD("maple_microphone::dma MDCF_MICControl function (1st word) %#010x\n", function); @@ -762,14 +763,14 @@ struct maple_microphone: maple_base 0x00000002 Disables recording * */ - u32 subcommand=r32(); + u32 secondword=r32(); //LOGD("maple_microphone::dma MDCF_MICControl subcommand (2nd word) %#010x\n", subcommand); - u32 cmd = subcommand & 0xFF; //just get last byte for now, deal with params later + u32 subcommand = secondword & 0xFF; //just get last byte for now, deal with params later //LOGD("maple_microphone::dma MDCF_MICControl (3rd word) %#010x\n", r32()); //LOGD("maple_microphone::dma MDCF_MICControl (4th word) %#010x\n", r32()); - switch(cmd) + switch(subcommand) { case 0x01: { @@ -777,7 +778,7 @@ struct maple_microphone: maple_base //maximum size of a Maple Bus packet is 256 words (1024 bytes) //maybe i should start with 512 (same as vmu) u8* micdata=(u8*)malloc(512); - get_mic_data(micdata); //this is crashing (jni issue) + get_mic_data(micdata); wptr(micdata, 512); return MDRS_DataTransfer; @@ -790,10 +791,12 @@ struct maple_microphone: maple_base case 0x03: return MDRS_DeviceReply; default: + LOGD("maple_microphone::dma UNHANDLED secondword %#010x\n",secondword); break; } } default: + LOGD("maple_microphone::dma UNHANDLED function %#010x\n",function); break; } } diff --git a/shell/android/jni/src/Android.cpp b/shell/android/jni/src/Android.cpp index 2d8eea413..d995d7ba1 100644 --- a/shell/android/jni/src/Android.cpp +++ b/shell/android/jni/src/Android.cpp @@ -214,9 +214,8 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_run(JNIEnv *env,jobject o JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_setupMic(JNIEnv *env,jobject obj,jobject sip) { - sipemu = sip; - getmicdata = env->GetMethodID(env->GetObjectClass(sipemu),"getData","()[B"); - + sipemu = env->NewGlobalRef(sip); + getmicdata = env->GetMethodID(env->GetObjectClass(sipemu),"getData","()[B"); } JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_stop(JNIEnv *env,jobject obj) From 841ed659ae9d27c2c1f9d98611a75ed7d301d264 Mon Sep 17 00:00:00 2001 From: Bryan Barnes Date: Thu, 16 Jan 2014 02:25:37 -0500 Subject: [PATCH 07/19] AWWWW YEA SOMEONE TRY THIS --- shell/android/jni/src/Android.cpp | 5 +++++ shell/android/src/com/reicast/emulator/SipEmulator.java | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/shell/android/jni/src/Android.cpp b/shell/android/jni/src/Android.cpp index d995d7ba1..14d0b7e51 100644 --- a/shell/android/jni/src/Android.cpp +++ b/shell/android/jni/src/Android.cpp @@ -349,7 +349,12 @@ void get_mic_data(u8* buffer) { LOGD("get_mic_data called"); jbyteArray jdata = (jbyteArray)jenv->CallObjectMethod(sipemu,getmicdata); + if(jdata==NULL){ + LOGD("get_mic_data jdata NULL"); + return; + } LOGD("CallObjectMethod happened"); jenv->GetByteArrayRegion(jdata, 0, 512, (jbyte*)buffer); LOGD("GetByteArrayRegion happened"); + jenv->DeleteLocalRef(jdata); } diff --git a/shell/android/src/com/reicast/emulator/SipEmulator.java b/shell/android/src/com/reicast/emulator/SipEmulator.java index ea6dcc2c6..8a93a15bd 100644 --- a/shell/android/src/com/reicast/emulator/SipEmulator.java +++ b/shell/android/src/com/reicast/emulator/SipEmulator.java @@ -23,6 +23,7 @@ public class SipEmulator extends Thread{ private Thread recordThread; private boolean continueRecording; + private boolean firstGet; /* 16-bit PCM @ 11025 hz @@ -51,6 +52,8 @@ public class SipEmulator extends Thread{ bytesReadBuffer = new LinkedList(); + continueRecording = false; + firstGet = true; } @@ -73,6 +76,12 @@ public class SipEmulator extends Thread{ public byte[] getData(){ //Log.d(TAG, "SipEmulator getData called"); Log.d(TAG, "SipEmulator getData bytesReadBuffer size: "+bytesReadBuffer.size()); + if(firstGet){ + firstGet = false; + byte[] last = bytesReadBuffer.removeLast(); + bytesReadBuffer.clear(); + return last; + } return bytesReadBuffer.poll(); } From d839e8d70da53a92a3a1b686176b1862c7a754b4 Mon Sep 17 00:00:00 2001 From: hooby3dfx Date: Thu, 16 Jan 2014 15:51:12 -0500 Subject: [PATCH 08/19] minor hygiene --- docs/microphone support notes.txt | 23 ++++++++++++++----- .../src/com/reicast/emulator/SipEmulator.java | 12 ++++++---- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/docs/microphone support notes.txt b/docs/microphone support notes.txt index 93ad45054..078d98975 100644 --- a/docs/microphone support notes.txt +++ b/docs/microphone support notes.txt @@ -1,12 +1,23 @@ -1/13/2014 hooby3dfx +1/13/2014 hooby3dfx initial plan +1/16/2014 hooby3dfx updated with progress, more details on how it works + general info links from bluecrab: http://dreamcast-talk.com/forum/viewtopic.php?t=2921&f=5 kallistios driver (could use for test app): http://cadcdev.sourceforge.net/docs/kos-2.0.0/sip_8h.html maplebus: https://web.archive.org/web/20101117090620/http://mc.pp.se/dc/maplebus.html plan: --figure out the mic commands that seaman is looking for and implement them --create mic test app (consult bluecrab) --figure out how the game/dc requests the audio (or how the mic just streams)... --for poc just create some kind of global way to pass the audio data from android mic interface directly to the maple_base instance --cleanup \ No newline at end of file +-figure out the mic commands that seaman is looking for and implement them [DONE (a couple commands not supported)] +-create mic test app (consult bluecrab) [Otoire tunes should be great and the other real games that support mic - should compile list] +-figure out how the game/dc requests the audio (or how the mic just streams)... [Done - at least in seaman DC tells mic to start recording then polls the mic pretty frequently for data] +-for poc just create some kind of global way to pass the audio data from android mic interface directly to the maple_base instance [Done] +-test +-cleanup +-test more + + +16-bit PCM @ 11025 hz +== 176.4 kbit/s +== 22050 bytes/s + +maximum size of a Maple Bus packet is 256 words (1024 bytes) \ No newline at end of file diff --git a/shell/android/src/com/reicast/emulator/SipEmulator.java b/shell/android/src/com/reicast/emulator/SipEmulator.java index 8a93a15bd..4204aff8f 100644 --- a/shell/android/src/com/reicast/emulator/SipEmulator.java +++ b/shell/android/src/com/reicast/emulator/SipEmulator.java @@ -16,7 +16,7 @@ public class SipEmulator extends Thread{ //this needs to get set to the amount the mic normally sends per data request //--->target 512! static final int ONE_BLIP_SIZE = 512; - static final long TIME_TO_WAIT_BETWEEN_POLLS = 1000 / 44; //poll every ~23 ms + static final long TIME_TO_WAIT_BETWEEN_POLLS = 1000 / (BUFFER_SIZE / ONE_BLIP_SIZE); private AudioRecord record; private LinkedList bytesReadBuffer; @@ -78,13 +78,17 @@ public class SipEmulator extends Thread{ Log.d(TAG, "SipEmulator getData bytesReadBuffer size: "+bytesReadBuffer.size()); if(firstGet){ firstGet = false; - byte[] last = bytesReadBuffer.removeLast(); - bytesReadBuffer.clear(); - return last; + return catchUp(); } return bytesReadBuffer.poll(); } + private byte[] catchUp(){ + byte[] last = bytesReadBuffer.removeLast(); + bytesReadBuffer.clear(); + return last; + } + public void configSomething(int what, int setting){ Log.d(TAG, "SipEmulator configSomething called"); From 800526ddcd9e4b30776a1e3f57f7eea174c7d7ac Mon Sep 17 00:00:00 2001 From: Bryan Barnes Date: Sat, 18 Jan 2014 16:54:18 -0500 Subject: [PATCH 09/19] progress -some cleanup -handling of retransmit -got rid of needless sleeping in record thread -some latency handling --- core/hw/maple/maple_devs.cpp | 24 +++++++++++++++---- core/hw/maple/maple_devs.h | 3 ++- shell/android/jni/src/Android.cpp | 9 ++----- .../src/com/reicast/emulator/SipEmulator.java | 19 ++++++++------- 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/core/hw/maple/maple_devs.cpp b/core/hw/maple/maple_devs.cpp index 7bdc1575e..599a04af7 100755 --- a/core/hw/maple/maple_devs.cpp +++ b/core/hw/maple/maple_devs.cpp @@ -656,6 +656,13 @@ struct maple_sega_vmu: maple_base struct maple_microphone: maple_base { + u8 micdata[SIZE_OF_MIC_DATA]; + + virtual void OnSetup() + { + memset(micdata,0,sizeof(micdata)); + } + virtual u32 dma(u32 cmd) { //printf("maple_microphone::dma Called 0x%X;Command %d\n",this->maple_port,cmd); @@ -775,21 +782,28 @@ struct maple_microphone: maple_base case 0x01: { LOGD("maple_microphone::dma MDCF_MICControl someone wants some data!"); - //maximum size of a Maple Bus packet is 256 words (1024 bytes) - //maybe i should start with 512 (same as vmu) - u8* micdata=(u8*)malloc(512); + + //do i need this? + //w32(MFID_4_Mic); + get_mic_data(micdata); - wptr(micdata, 512); + wptr(micdata, SIZE_OF_MIC_DATA); return MDRS_DataTransfer; } case 0x02: - LOGD("maple_microphone::dma MDCF_MICControl toggle recording!"); + LOGD("maple_microphone::dma MDCF_MICControl toggle recording %#010x\n",secondword); //this is where i should start recording... return MDRS_DeviceReply; case 0x03: + LOGD("maple_microphone::dma MDCF_MICControl set gain %#010x\n",secondword); return MDRS_DeviceReply; + case MDRE_TransminAgain: + LOGD("maple_microphone::dma MDCF_MICControl MDRE_TransminAgain"); + //w32(MFID_4_Mic); + wptr(micdata, SIZE_OF_MIC_DATA); + return MDRS_DataTransfer; default: LOGD("maple_microphone::dma UNHANDLED secondword %#010x\n",secondword); break; diff --git a/core/hw/maple/maple_devs.h b/core/hw/maple/maple_devs.h index 9a7daadd7..655ddc0d9 100644 --- a/core/hw/maple/maple_devs.h +++ b/core/hw/maple/maple_devs.h @@ -29,4 +29,5 @@ struct maple_device }; maple_device* maple_Create(MapleDeviceType type); -void get_mic_data(u8* buffer); +#define SIZE_OF_MIC_DATA 512 //ALSO DEFINED IN SipEmulator.java +void get_mic_data(u8* buffer); //implemented in Android.cpp diff --git a/shell/android/jni/src/Android.cpp b/shell/android/jni/src/Android.cpp index 14d0b7e51..e9499d8cf 100644 --- a/shell/android/jni/src/Android.cpp +++ b/shell/android/jni/src/Android.cpp @@ -39,8 +39,6 @@ extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_setupMic(JNIEnv *env,jobject obj,jobject sip) __attribute__((visibility("default"))); }; -#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "Android.cpp JNI wtf", __VA_ARGS__) - void egl_stealcntx(); void SetApplicationPath(wchar *path); @@ -347,14 +345,11 @@ bool os_IsAudioBuffered() void get_mic_data(u8* buffer) { - LOGD("get_mic_data called"); jbyteArray jdata = (jbyteArray)jenv->CallObjectMethod(sipemu,getmicdata); if(jdata==NULL){ - LOGD("get_mic_data jdata NULL"); + LOGW("get_mic_data NULL"); return; } - LOGD("CallObjectMethod happened"); - jenv->GetByteArrayRegion(jdata, 0, 512, (jbyte*)buffer); - LOGD("GetByteArrayRegion happened"); + jenv->GetByteArrayRegion(jdata, 0, SIZE_OF_MIC_DATA, (jbyte*)buffer); jenv->DeleteLocalRef(jdata); } diff --git a/shell/android/src/com/reicast/emulator/SipEmulator.java b/shell/android/src/com/reicast/emulator/SipEmulator.java index 4204aff8f..a4206080c 100644 --- a/shell/android/src/com/reicast/emulator/SipEmulator.java +++ b/shell/android/src/com/reicast/emulator/SipEmulator.java @@ -7,16 +7,16 @@ import android.media.AudioRecord; import android.media.MediaRecorder; import android.util.Log; -public class SipEmulator extends Thread{ +public class SipEmulator extends Thread { static final String TAG = "SipEmulator"; //one second of audio data in bytes static final int BUFFER_SIZE = 22050; //this needs to get set to the amount the mic normally sends per data request - //--->target 512! - static final int ONE_BLIP_SIZE = 512; - static final long TIME_TO_WAIT_BETWEEN_POLLS = 1000 / (BUFFER_SIZE / ONE_BLIP_SIZE); + //...cant be bigger than a maple packet + static final int ONE_BLIP_SIZE = 512; //ALSO DEFINED IN maple_devs.h + //static final long TIME_TO_WAIT_BETWEEN_POLLS = 1000 / (BUFFER_SIZE / ONE_BLIP_SIZE); private AudioRecord record; private LinkedList bytesReadBuffer; @@ -69,14 +69,14 @@ public class SipEmulator extends Thread{ public void stopRecording(){ Log.d(TAG, "SipEmulator stopRecording called"); - record.stop(); continueRecording = false; + record.stop(); } public byte[] getData(){ //Log.d(TAG, "SipEmulator getData called"); Log.d(TAG, "SipEmulator getData bytesReadBuffer size: "+bytesReadBuffer.size()); - if(firstGet){ + if(firstGet || bytesReadBuffer.size()>50){//50 blips is about 2 seconds! firstGet = false; return catchUp(); } @@ -84,6 +84,7 @@ public class SipEmulator extends Thread{ } private byte[] catchUp(){ + Log.d(TAG, "SipEmulator catchUp"); byte[] last = bytesReadBuffer.removeLast(); bytesReadBuffer.clear(); return last; @@ -105,15 +106,17 @@ public class SipEmulator extends Thread{ while(continueRecording){ byte[] freshData = new byte[ONE_BLIP_SIZE]; - int bytesRead = record.read(freshData, 0, ONE_BLIP_SIZE); + // read blocks + int bytesRead = record.read(freshData, 0, ONE_BLIP_SIZE); //Log.d(TAG, "recordThread recorded: "+bytesRead); bytesReadBuffer.add(freshData); - + /* try { Thread.sleep(TIME_TO_WAIT_BETWEEN_POLLS); } catch (InterruptedException e) { e.printStackTrace(); } + */ } } From e1970cf01d7a6c7ca8817d5911e356794216c6ee Mon Sep 17 00:00:00 2001 From: Bryan Barnes Date: Sat, 18 Jan 2014 18:19:59 -0500 Subject: [PATCH 10/19] notes and manifest tweak --- docs/microphone support notes.txt | 5 +++-- shell/android/AndroidManifest.xml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/microphone support notes.txt b/docs/microphone support notes.txt index 078d98975..1564cb33e 100644 --- a/docs/microphone support notes.txt +++ b/docs/microphone support notes.txt @@ -11,9 +11,10 @@ plan: -create mic test app (consult bluecrab) [Otoire tunes should be great and the other real games that support mic - should compile list] -figure out how the game/dc requests the audio (or how the mic just streams)... [Done - at least in seaman DC tells mic to start recording then polls the mic pretty frequently for data] -for poc just create some kind of global way to pass the audio data from android mic interface directly to the maple_base instance [Done] --test --cleanup +-test [Created recording in Otoire, imported VMS into Demul and got the sound! Seaman needs more testing] +-cleanup [Partially done, lots of logging left] -test more +-integrate into settings ui 16-bit PCM @ 11025 hz diff --git a/shell/android/AndroidManifest.xml b/shell/android/AndroidManifest.xml index cdcac06e2..e4512c101 100644 --- a/shell/android/AndroidManifest.xml +++ b/shell/android/AndroidManifest.xml @@ -11,7 +11,7 @@ - + From 0c11acb931ad189ea0ef2df05d748a96ceadc187 Mon Sep 17 00:00:00 2001 From: Bryan Barnes Date: Sun, 19 Jan 2014 12:35:52 -0500 Subject: [PATCH 11/19] better conformity to spec --- core/hw/maple/maple_devs.cpp | 30 +++++++++++++------ core/hw/maple/maple_devs.h | 4 +-- docs/microphone support notes.txt | 15 +++++++++- shell/android/jni/src/Android.cpp | 5 ++-- .../src/com/reicast/emulator/SipEmulator.java | 4 +-- 5 files changed, 42 insertions(+), 16 deletions(-) diff --git a/core/hw/maple/maple_devs.cpp b/core/hw/maple/maple_devs.cpp index 599a04af7..28c643a39 100755 --- a/core/hw/maple/maple_devs.cpp +++ b/core/hw/maple/maple_devs.cpp @@ -706,6 +706,7 @@ struct maple_microphone: maple_base case MDCF_GetCondition: { + LOGD("maple_microphone::dma MDCF_GetCondition"); //this was copied from the controller case with just the id replaced! //PlainJoystickState pjs; @@ -781,14 +782,25 @@ struct maple_microphone: maple_base { case 0x01: { - LOGD("maple_microphone::dma MDCF_MICControl someone wants some data!"); + LOGD("maple_microphone::dma MDCF_MICControl someone wants some data! (2nd word) %#010x\n", subcommand); - //do i need this? - //w32(MFID_4_Mic); + w32(MFID_4_Mic); + + //from what i can tell this is up to spec but results in transmit again + //w32(secondword); + + //32 bit header + w8(0x04);//status (just the bit for recording) + w8(0x0f);//gain (default) + w8(0);//exp ? + + if(get_mic_data(micdata)){ + w8(240);//ct (240 samples) + wptr(micdata, SIZE_OF_MIC_DATA); + }else{ + w8(0); + } - get_mic_data(micdata); - wptr(micdata, SIZE_OF_MIC_DATA); - return MDRS_DataTransfer; } case 0x02: @@ -801,9 +813,9 @@ struct maple_microphone: maple_base return MDRS_DeviceReply; case MDRE_TransminAgain: LOGD("maple_microphone::dma MDCF_MICControl MDRE_TransminAgain"); - //w32(MFID_4_Mic); - wptr(micdata, SIZE_OF_MIC_DATA); - return MDRS_DataTransfer; + //apparently this doesnt matter + //wptr(micdata, SIZE_OF_MIC_DATA); + return MDRS_DeviceReply;//MDRS_DataTransfer; default: LOGD("maple_microphone::dma UNHANDLED secondword %#010x\n",secondword); break; diff --git a/core/hw/maple/maple_devs.h b/core/hw/maple/maple_devs.h index 655ddc0d9..936fc4fd6 100644 --- a/core/hw/maple/maple_devs.h +++ b/core/hw/maple/maple_devs.h @@ -29,5 +29,5 @@ struct maple_device }; maple_device* maple_Create(MapleDeviceType type); -#define SIZE_OF_MIC_DATA 512 //ALSO DEFINED IN SipEmulator.java -void get_mic_data(u8* buffer); //implemented in Android.cpp +#define SIZE_OF_MIC_DATA 480 //ALSO DEFINED IN SipEmulator.java +int get_mic_data(u8* buffer); //implemented in Android.cpp diff --git a/docs/microphone support notes.txt b/docs/microphone support notes.txt index 1564cb33e..8f5a3bace 100644 --- a/docs/microphone support notes.txt +++ b/docs/microphone support notes.txt @@ -21,4 +21,17 @@ plan: == 176.4 kbit/s == 22050 bytes/s -maximum size of a Maple Bus packet is 256 words (1024 bytes) \ No newline at end of file +maximum size of a Maple Bus packet is 256 words (1024 bytes) + + +================ +Games that can use mic: +-Seaman +-Alien Front Online +-Planet Ring +-Mr Driller +-Otoire +-Propeller Arena +-Visual Park +-??? + diff --git a/shell/android/jni/src/Android.cpp b/shell/android/jni/src/Android.cpp index e9499d8cf..3ae1519b8 100644 --- a/shell/android/jni/src/Android.cpp +++ b/shell/android/jni/src/Android.cpp @@ -343,13 +343,14 @@ bool os_IsAudioBuffered() return jenv->CallIntMethod(track,writemid,jsamples,-1)==0; } -void get_mic_data(u8* buffer) +int get_mic_data(u8* buffer) { jbyteArray jdata = (jbyteArray)jenv->CallObjectMethod(sipemu,getmicdata); if(jdata==NULL){ LOGW("get_mic_data NULL"); - return; + return 0; } jenv->GetByteArrayRegion(jdata, 0, SIZE_OF_MIC_DATA, (jbyte*)buffer); jenv->DeleteLocalRef(jdata); + return 1; } diff --git a/shell/android/src/com/reicast/emulator/SipEmulator.java b/shell/android/src/com/reicast/emulator/SipEmulator.java index a4206080c..5749f32ce 100644 --- a/shell/android/src/com/reicast/emulator/SipEmulator.java +++ b/shell/android/src/com/reicast/emulator/SipEmulator.java @@ -15,8 +15,8 @@ public class SipEmulator extends Thread { static final int BUFFER_SIZE = 22050; //this needs to get set to the amount the mic normally sends per data request //...cant be bigger than a maple packet - static final int ONE_BLIP_SIZE = 512; //ALSO DEFINED IN maple_devs.h - //static final long TIME_TO_WAIT_BETWEEN_POLLS = 1000 / (BUFFER_SIZE / ONE_BLIP_SIZE); + // 240 16 (or 14) bit samples + static final int ONE_BLIP_SIZE = 480; //ALSO DEFINED IN maple_devs.h private AudioRecord record; private LinkedList bytesReadBuffer; From 7e8bc2972b4867ad615ca572818d66dbc018ec37 Mon Sep 17 00:00:00 2001 From: Bryan Barnes Date: Fri, 31 Jan 2014 19:57:12 -0500 Subject: [PATCH 12/19] merge from master i hope --- shell/android/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/android/AndroidManifest.xml b/shell/android/AndroidManifest.xml index e4512c101..41237685c 100644 --- a/shell/android/AndroidManifest.xml +++ b/shell/android/AndroidManifest.xml @@ -15,7 +15,7 @@ - + Date: Sat, 1 Feb 2014 10:44:06 -0500 Subject: [PATCH 13/19] This is ready to go -Added config to input fragment -Reduced logging -Init the mic at the right time during startup so that port 2 either gets vmu or mic -Has not been tested on device without mic -Needs more testing in games --- core/hw/maple/maple_cfg.cpp | 12 ++++++++- core/hw/maple/maple_devs.cpp | 21 +++++++-------- shell/android/jni/src/Android.cpp | 4 ++- shell/android/res/layout/input_fragment.xml | 26 +++++++++++++++++++ shell/android/res/values/strings.xml | 1 + .../com/reicast/emulator/GL2JNIActivity.java | 14 +++++----- .../com/reicast/emulator/InputFragment.java | 11 ++++++++ .../src/com/reicast/emulator/SipEmulator.java | 6 ++--- 8 files changed, 73 insertions(+), 22 deletions(-) diff --git a/core/hw/maple/maple_cfg.cpp b/core/hw/maple/maple_cfg.cpp index 8ed2b09cc..67d1d84e1 100644 --- a/core/hw/maple/maple_cfg.cpp +++ b/core/hw/maple/maple_cfg.cpp @@ -27,6 +27,8 @@ extern u32 vks[4]; extern s8 joyx[4],joyy[4]; extern u8 rt[4],lt[4]; +bool micpluggedin = false; + u8 GetBtFromSgn(s8 val) { return val+128; @@ -72,7 +74,15 @@ void mcfg_CreateDevices() #ifdef HAS_VMU mcfg_Create(MDT_SegaVMU,0,0); - mcfg_Create(MDT_Microphone,0,1); + if(micpluggedin){ + LOGI("maple_cfg::mcfg_CreateDevices micpluggedin!"); + mcfg_Create(MDT_Microphone,0,1); + } + else + { + LOGI("maple_cfg::mcfg_CreateDevices mic NOT plugged in"); + mcfg_Create(MDT_SegaVMU,0,1); + } #endif } diff --git a/core/hw/maple/maple_devs.cpp b/core/hw/maple/maple_devs.cpp index 28c643a39..65cea76db 100755 --- a/core/hw/maple/maple_devs.cpp +++ b/core/hw/maple/maple_devs.cpp @@ -20,7 +20,6 @@ const char* maple_sega_mic_name = "MicDevice for Dreameye"; const char* maple_sega_brand = "Produced By or Under License From SEGA ENTERPRISES,LTD."; #define HAS_VMU -#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "maple_devs", __VA_ARGS__) enum MapleFunctionID { @@ -671,7 +670,7 @@ struct maple_microphone: maple_base switch (cmd) { case MDC_DeviceRequest: - LOGD("maple_microphone::dma MDC_DeviceRequest"); + LOGI("maple_microphone::dma MDC_DeviceRequest"); //this was copied from the controller case with just the id and name replaced! //caps @@ -706,7 +705,7 @@ struct maple_microphone: maple_base case MDCF_GetCondition: { - LOGD("maple_microphone::dma MDCF_GetCondition"); + LOGI("maple_microphone::dma MDCF_GetCondition"); //this was copied from the controller case with just the id replaced! //PlainJoystickState pjs; @@ -743,7 +742,7 @@ struct maple_microphone: maple_base case MDC_DeviceReset: //uhhh do nothing? - LOGD("maple_microphone::dma MDC_DeviceReset"); + LOGI("maple_microphone::dma MDC_DeviceReset"); return MDRS_DeviceReply; case MDCF_MICControl: @@ -782,7 +781,7 @@ struct maple_microphone: maple_base { case 0x01: { - LOGD("maple_microphone::dma MDCF_MICControl someone wants some data! (2nd word) %#010x\n", subcommand); + //LOGD("maple_microphone::dma MDCF_MICControl someone wants some data! (2nd word) %#010x\n", subcommand); w32(MFID_4_Mic); @@ -804,31 +803,31 @@ struct maple_microphone: maple_base return MDRS_DataTransfer; } case 0x02: - LOGD("maple_microphone::dma MDCF_MICControl toggle recording %#010x\n",secondword); + LOGI("maple_microphone::dma MDCF_MICControl toggle recording %#010x\n",secondword); //this is where i should start recording... return MDRS_DeviceReply; case 0x03: - LOGD("maple_microphone::dma MDCF_MICControl set gain %#010x\n",secondword); + LOGI("maple_microphone::dma MDCF_MICControl set gain %#010x\n",secondword); return MDRS_DeviceReply; case MDRE_TransminAgain: - LOGD("maple_microphone::dma MDCF_MICControl MDRE_TransminAgain"); + LOGW("maple_microphone::dma MDCF_MICControl MDRE_TransminAgain"); //apparently this doesnt matter //wptr(micdata, SIZE_OF_MIC_DATA); return MDRS_DeviceReply;//MDRS_DataTransfer; default: - LOGD("maple_microphone::dma UNHANDLED secondword %#010x\n",secondword); + LOGW("maple_microphone::dma UNHANDLED secondword %#010x\n",secondword); break; } } default: - LOGD("maple_microphone::dma UNHANDLED function %#010x\n",function); + LOGW("maple_microphone::dma UNHANDLED function %#010x\n",function); break; } } default: - LOGD("maple_microphone::dma UNHANDLED MAPLE COMMAND %d\n",cmd); + LOGW("maple_microphone::dma UNHANDLED MAPLE COMMAND %d\n",cmd); return MDRE_UnknownFunction; } } diff --git a/shell/android/jni/src/Android.cpp b/shell/android/jni/src/Android.cpp index 3ae1519b8..b4eb39a28 100644 --- a/shell/android/jni/src/Android.cpp +++ b/shell/android/jni/src/Android.cpp @@ -54,6 +54,7 @@ bool gles_init(); //extern cResetEvent rs,re; extern int screen_width,screen_height; +extern bool micpluggedin; static u64 tvs_base; static char CurFileName[256]; @@ -214,6 +215,7 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_setupMic(JNIEnv *env,jobj { sipemu = env->NewGlobalRef(sip); getmicdata = env->GetMethodID(env->GetObjectClass(sipemu),"getData","()[B"); + micpluggedin = true; } JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_stop(JNIEnv *env,jobject obj) @@ -347,7 +349,7 @@ int get_mic_data(u8* buffer) { jbyteArray jdata = (jbyteArray)jenv->CallObjectMethod(sipemu,getmicdata); if(jdata==NULL){ - LOGW("get_mic_data NULL"); + //LOGW("get_mic_data NULL"); return 0; } jenv->GetByteArrayRegion(jdata, 0, SIZE_OF_MIC_DATA, (jbyte*)buffer); diff --git a/shell/android/res/layout/input_fragment.xml b/shell/android/res/layout/input_fragment.xml index 8419268c2..1de0b7213 100644 --- a/shell/android/res/layout/input_fragment.xml +++ b/shell/android/res/layout/input_fragment.xml @@ -92,6 +92,32 @@ android:ems="8" android:text="@string/launch_editor" /> + + + + + + + + + + diff --git a/shell/android/res/values/strings.xml b/shell/android/res/values/strings.xml index 68f579c36..d99f74aa9 100644 --- a/shell/android/res/values/strings.xml +++ b/shell/android/res/values/strings.xml @@ -46,6 +46,7 @@ Enable Custom Key Layout Enable Compatibility Mode Joystick Uses DPAD Layout + Mic in port 2 Customize Physical Controls Modify Controller diff --git a/shell/android/src/com/reicast/emulator/GL2JNIActivity.java b/shell/android/src/com/reicast/emulator/GL2JNIActivity.java index 64931cff0..99d6d2f87 100644 --- a/shell/android/src/com/reicast/emulator/GL2JNIActivity.java +++ b/shell/android/src/com/reicast/emulator/GL2JNIActivity.java @@ -313,6 +313,14 @@ public class GL2JNIActivity extends Activity { } else { runCompatibilityMode(); } + + //setup mic + boolean micPluggedIn = prefs.getBoolean("mic_plugged_in", false); + if(micPluggedIn){ + SipEmulator sip = new SipEmulator(); + sip.startRecording(); + JNIdc.setupMic(sip); + } // When viewing a resource, pass its URI to the native code for opening Intent intent = getIntent(); @@ -325,12 +333,6 @@ public class GL2JNIActivity extends Activity { Toast.makeText(getApplicationContext(), "Press the back button for a menu", Toast.LENGTH_SHORT).show(); - - - //totally hijacking this to setup mic - SipEmulator sip = new SipEmulator(); - sip.startRecording(); - JNIdc.setupMic(sip); } diff --git a/shell/android/src/com/reicast/emulator/InputFragment.java b/shell/android/src/com/reicast/emulator/InputFragment.java index 77c567bc2..2ac6c3cce 100644 --- a/shell/android/src/com/reicast/emulator/InputFragment.java +++ b/shell/android/src/com/reicast/emulator/InputFragment.java @@ -39,6 +39,7 @@ public class InputFragment extends Fragment { private AlertDialog alertDialogSelectController; private SharedPreferences sharedPreferences; private Switch switchTouchVibrationEnabled; + private Switch micPluggedIntoFirstController; public MOGAInput moga = new MOGAInput(); @@ -106,6 +107,16 @@ public class InputFragment extends Fragment { } switchTouchVibrationEnabled.setOnCheckedChangeListener(touch_vibration); + micPluggedIntoFirstController = (Switch) getView().findViewById( + R.id.micInPort2); + boolean micPluggedIn = sharedPreferences.getBoolean("mic_plugged_in", false); + micPluggedIntoFirstController.setChecked(micPluggedIn); + micPluggedIntoFirstController.setOnCheckedChangeListener(new OnCheckedChangeListener() { + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + sharedPreferences.edit().putBoolean("mic_plugged_in", isChecked).commit(); + } + }); + Button buttonKeycodeEditor = (Button) getView().findViewById( R.id.buttonKeycodeEditor); buttonKeycodeEditor.setOnClickListener(new View.OnClickListener() { diff --git a/shell/android/src/com/reicast/emulator/SipEmulator.java b/shell/android/src/com/reicast/emulator/SipEmulator.java index 5749f32ce..49a3d3593 100644 --- a/shell/android/src/com/reicast/emulator/SipEmulator.java +++ b/shell/android/src/com/reicast/emulator/SipEmulator.java @@ -21,7 +21,7 @@ public class SipEmulator extends Thread { private AudioRecord record; private LinkedList bytesReadBuffer; - private Thread recordThread; + //private Thread recordThread; private boolean continueRecording; private boolean firstGet; @@ -58,10 +58,10 @@ public class SipEmulator extends Thread { public void startRecording(){ + Log.d(TAG, "SipEmulator startRecording called"); if(continueRecording){ return; } - Log.d(TAG, "SipEmulator startRecording called"); record.startRecording(); continueRecording = true; this.start(); @@ -75,7 +75,7 @@ public class SipEmulator extends Thread { public byte[] getData(){ //Log.d(TAG, "SipEmulator getData called"); - Log.d(TAG, "SipEmulator getData bytesReadBuffer size: "+bytesReadBuffer.size()); + //Log.d(TAG, "SipEmulator getData bytesReadBuffer size: "+bytesReadBuffer.size()); if(firstGet || bytesReadBuffer.size()>50){//50 blips is about 2 seconds! firstGet = false; return catchUp(); From f3416fda81274076ca72366ee866b9e8be588e14 Mon Sep 17 00:00:00 2001 From: Bryan Barnes Date: Sat, 1 Feb 2014 12:37:04 -0500 Subject: [PATCH 14/19] grr managed to add some instability, investigating --- docs/microphone support notes.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/microphone support notes.txt b/docs/microphone support notes.txt index 8f5a3bace..cc22ba69c 100644 --- a/docs/microphone support notes.txt +++ b/docs/microphone support notes.txt @@ -33,5 +33,5 @@ Games that can use mic: -Otoire -Propeller Arena -Visual Park --??? +-Kiteretsu Boys Gangagan From 208bcc0d793cf7be82b89826f81497cb2af937f3 Mon Sep 17 00:00:00 2001 From: Bryan Barnes Date: Sat, 1 Feb 2014 13:52:36 -0500 Subject: [PATCH 15/19] its verking! figured out issue, made mic setup simpler --- core/hw/maple/maple_cfg.cpp | 12 +----------- shell/android/jni/src/Android.cpp | 3 +-- .../src/com/reicast/emulator/GL2JNIActivity.java | 15 +++++++-------- 3 files changed, 9 insertions(+), 21 deletions(-) diff --git a/core/hw/maple/maple_cfg.cpp b/core/hw/maple/maple_cfg.cpp index 67d1d84e1..16e5a63fe 100644 --- a/core/hw/maple/maple_cfg.cpp +++ b/core/hw/maple/maple_cfg.cpp @@ -27,8 +27,6 @@ extern u32 vks[4]; extern s8 joyx[4],joyy[4]; extern u8 rt[4],lt[4]; -bool micpluggedin = false; - u8 GetBtFromSgn(s8 val) { return val+128; @@ -74,15 +72,7 @@ void mcfg_CreateDevices() #ifdef HAS_VMU mcfg_Create(MDT_SegaVMU,0,0); - if(micpluggedin){ - LOGI("maple_cfg::mcfg_CreateDevices micpluggedin!"); - mcfg_Create(MDT_Microphone,0,1); - } - else - { - LOGI("maple_cfg::mcfg_CreateDevices mic NOT plugged in"); - mcfg_Create(MDT_SegaVMU,0,1); - } + mcfg_Create(MDT_SegaVMU,0,1); #endif } diff --git a/shell/android/jni/src/Android.cpp b/shell/android/jni/src/Android.cpp index b4eb39a28..115c6000d 100644 --- a/shell/android/jni/src/Android.cpp +++ b/shell/android/jni/src/Android.cpp @@ -54,7 +54,6 @@ bool gles_init(); //extern cResetEvent rs,re; extern int screen_width,screen_height; -extern bool micpluggedin; static u64 tvs_base; static char CurFileName[256]; @@ -215,7 +214,7 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_setupMic(JNIEnv *env,jobj { sipemu = env->NewGlobalRef(sip); getmicdata = env->GetMethodID(env->GetObjectClass(sipemu),"getData","()[B"); - micpluggedin = true; + mcfg_Create(MDT_Microphone,0,1); } JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_stop(JNIEnv *env,jobject obj) diff --git a/shell/android/src/com/reicast/emulator/GL2JNIActivity.java b/shell/android/src/com/reicast/emulator/GL2JNIActivity.java index 99d6d2f87..411c33787 100644 --- a/shell/android/src/com/reicast/emulator/GL2JNIActivity.java +++ b/shell/android/src/com/reicast/emulator/GL2JNIActivity.java @@ -313,14 +313,6 @@ public class GL2JNIActivity extends Activity { } else { runCompatibilityMode(); } - - //setup mic - boolean micPluggedIn = prefs.getBoolean("mic_plugged_in", false); - if(micPluggedIn){ - SipEmulator sip = new SipEmulator(); - sip.startRecording(); - JNIdc.setupMic(sip); - } // When viewing a resource, pass its URI to the native code for opening Intent intent = getIntent(); @@ -334,6 +326,13 @@ public class GL2JNIActivity extends Activity { Toast.makeText(getApplicationContext(), "Press the back button for a menu", Toast.LENGTH_SHORT).show(); + //setup mic + boolean micPluggedIn = prefs.getBoolean("mic_plugged_in", false); + if(micPluggedIn){ + SipEmulator sip = new SipEmulator(); + sip.startRecording(); + JNIdc.setupMic(sip); + } } private void runCompatibilityMode() { From 2403d1344047011fc406b6c0d77f83538fbfd7e6 Mon Sep 17 00:00:00 2001 From: Bryan Barnes Date: Sat, 1 Feb 2014 14:05:09 -0500 Subject: [PATCH 16/19] umm ok its one of those things where the logging makes it work! not sure whats up, but without the additional logging it crashes. --- core/hw/maple/maple_devs.cpp | 2 +- shell/android/jni/src/Android.cpp | 2 +- shell/android/src/com/reicast/emulator/SipEmulator.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/hw/maple/maple_devs.cpp b/core/hw/maple/maple_devs.cpp index 65cea76db..2532133e4 100755 --- a/core/hw/maple/maple_devs.cpp +++ b/core/hw/maple/maple_devs.cpp @@ -781,7 +781,7 @@ struct maple_microphone: maple_base { case 0x01: { - //LOGD("maple_microphone::dma MDCF_MICControl someone wants some data! (2nd word) %#010x\n", subcommand); + LOGI("maple_microphone::dma MDCF_MICControl someone wants some data! (2nd word) %#010x\n", subcommand); w32(MFID_4_Mic); diff --git a/shell/android/jni/src/Android.cpp b/shell/android/jni/src/Android.cpp index 115c6000d..3d1fdcfc8 100644 --- a/shell/android/jni/src/Android.cpp +++ b/shell/android/jni/src/Android.cpp @@ -348,7 +348,7 @@ int get_mic_data(u8* buffer) { jbyteArray jdata = (jbyteArray)jenv->CallObjectMethod(sipemu,getmicdata); if(jdata==NULL){ - //LOGW("get_mic_data NULL"); + LOGW("get_mic_data NULL"); return 0; } jenv->GetByteArrayRegion(jdata, 0, SIZE_OF_MIC_DATA, (jbyte*)buffer); diff --git a/shell/android/src/com/reicast/emulator/SipEmulator.java b/shell/android/src/com/reicast/emulator/SipEmulator.java index 49a3d3593..11edae6bc 100644 --- a/shell/android/src/com/reicast/emulator/SipEmulator.java +++ b/shell/android/src/com/reicast/emulator/SipEmulator.java @@ -75,7 +75,7 @@ public class SipEmulator extends Thread { public byte[] getData(){ //Log.d(TAG, "SipEmulator getData called"); - //Log.d(TAG, "SipEmulator getData bytesReadBuffer size: "+bytesReadBuffer.size()); + Log.d(TAG, "SipEmulator getData bytesReadBuffer size: "+bytesReadBuffer.size()); if(firstGet || bytesReadBuffer.size()>50){//50 blips is about 2 seconds! firstGet = false; return catchUp(); From 3e33efa3ca6314a306b459ffab0b017d2ddae3fc Mon Sep 17 00:00:00 2001 From: Bryan Barnes Date: Sat, 1 Feb 2014 22:36:47 -0500 Subject: [PATCH 17/19] learning the hard way root cause found (i think). lesson: java functions called via jni dont handle exceptions/tell you what happens when they crash. --- core/hw/maple/maple_devs.cpp | 4 +--- shell/android/jni/src/Android.cpp | 2 +- .../android/src/com/reicast/emulator/SipEmulator.java | 10 +++++----- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/core/hw/maple/maple_devs.cpp b/core/hw/maple/maple_devs.cpp index 2532133e4..0bd2d06c4 100755 --- a/core/hw/maple/maple_devs.cpp +++ b/core/hw/maple/maple_devs.cpp @@ -781,7 +781,7 @@ struct maple_microphone: maple_base { case 0x01: { - LOGI("maple_microphone::dma MDCF_MICControl someone wants some data! (2nd word) %#010x\n", subcommand); + //LOGI("maple_microphone::dma MDCF_MICControl someone wants some data! (2nd word) %#010x\n", secondword); w32(MFID_4_Mic); @@ -804,8 +804,6 @@ struct maple_microphone: maple_base } case 0x02: LOGI("maple_microphone::dma MDCF_MICControl toggle recording %#010x\n",secondword); - //this is where i should start recording... - return MDRS_DeviceReply; case 0x03: LOGI("maple_microphone::dma MDCF_MICControl set gain %#010x\n",secondword); diff --git a/shell/android/jni/src/Android.cpp b/shell/android/jni/src/Android.cpp index 3d1fdcfc8..115c6000d 100644 --- a/shell/android/jni/src/Android.cpp +++ b/shell/android/jni/src/Android.cpp @@ -348,7 +348,7 @@ int get_mic_data(u8* buffer) { jbyteArray jdata = (jbyteArray)jenv->CallObjectMethod(sipemu,getmicdata); if(jdata==NULL){ - LOGW("get_mic_data NULL"); + //LOGW("get_mic_data NULL"); return 0; } jenv->GetByteArrayRegion(jdata, 0, SIZE_OF_MIC_DATA, (jbyte*)buffer); diff --git a/shell/android/src/com/reicast/emulator/SipEmulator.java b/shell/android/src/com/reicast/emulator/SipEmulator.java index 11edae6bc..828fa4917 100644 --- a/shell/android/src/com/reicast/emulator/SipEmulator.java +++ b/shell/android/src/com/reicast/emulator/SipEmulator.java @@ -1,6 +1,7 @@ package com.reicast.emulator; import java.util.LinkedList; +import java.util.concurrent.ConcurrentLinkedQueue; import android.media.AudioFormat; import android.media.AudioRecord; @@ -19,9 +20,8 @@ public class SipEmulator extends Thread { static final int ONE_BLIP_SIZE = 480; //ALSO DEFINED IN maple_devs.h private AudioRecord record; - private LinkedList bytesReadBuffer; + private ConcurrentLinkedQueue bytesReadBuffer; - //private Thread recordThread; private boolean continueRecording; private boolean firstGet; @@ -50,7 +50,7 @@ public class SipEmulator extends Thread { AudioFormat.ENCODING_PCM_16BIT, BUFFER_SIZE); - bytesReadBuffer = new LinkedList(); + bytesReadBuffer = new ConcurrentLinkedQueue(); continueRecording = false; firstGet = true; @@ -75,7 +75,7 @@ public class SipEmulator extends Thread { public byte[] getData(){ //Log.d(TAG, "SipEmulator getData called"); - Log.d(TAG, "SipEmulator getData bytesReadBuffer size: "+bytesReadBuffer.size()); + //Log.d(TAG, "SipEmulator getData bytesReadBuffer size: "+bytesReadBuffer.size()); if(firstGet || bytesReadBuffer.size()>50){//50 blips is about 2 seconds! firstGet = false; return catchUp(); @@ -85,7 +85,7 @@ public class SipEmulator extends Thread { private byte[] catchUp(){ Log.d(TAG, "SipEmulator catchUp"); - byte[] last = bytesReadBuffer.removeLast(); + byte[] last = bytesReadBuffer.poll(); bytesReadBuffer.clear(); return last; } From 6df7f8912c8c26ab91f5df3a0ecef2f2cb31cf1a Mon Sep 17 00:00:00 2001 From: Bryan Barnes Date: Sun, 2 Feb 2014 12:10:40 -0500 Subject: [PATCH 18/19] Prevent non-mic devices from doing this --- shell/android/res/values/strings.xml | 2 +- .../src/com/reicast/emulator/InputFragment.java | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/shell/android/res/values/strings.xml b/shell/android/res/values/strings.xml index d99f74aa9..afefb6302 100644 --- a/shell/android/res/values/strings.xml +++ b/shell/android/res/values/strings.xml @@ -46,7 +46,7 @@ Enable Custom Key Layout Enable Compatibility Mode Joystick Uses DPAD Layout - Mic in port 2 + Microphone plugged into port 2 Customize Physical Controls Modify Controller diff --git a/shell/android/src/com/reicast/emulator/InputFragment.java b/shell/android/src/com/reicast/emulator/InputFragment.java index 2ac6c3cce..59bf7e2a4 100644 --- a/shell/android/src/com/reicast/emulator/InputFragment.java +++ b/shell/android/src/com/reicast/emulator/InputFragment.java @@ -111,11 +111,18 @@ public class InputFragment extends Fragment { R.id.micInPort2); boolean micPluggedIn = sharedPreferences.getBoolean("mic_plugged_in", false); micPluggedIntoFirstController.setChecked(micPluggedIn); - micPluggedIntoFirstController.setOnCheckedChangeListener(new OnCheckedChangeListener() { - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - sharedPreferences.edit().putBoolean("mic_plugged_in", isChecked).commit(); - } - }); + if (getActivity().getPackageManager().hasSystemFeature( + "android.hardware.microphone")) { + //Microphone is present on the device + micPluggedIntoFirstController.setOnCheckedChangeListener(new OnCheckedChangeListener() { + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + sharedPreferences.edit().putBoolean("mic_plugged_in", isChecked).commit(); + } + }); + }else{ + micPluggedIntoFirstController.setEnabled(false); + } + Button buttonKeycodeEditor = (Button) getView().findViewById( R.id.buttonKeycodeEditor); From f571b187b0781b869b687c580ac7bea2a8c2a7f2 Mon Sep 17 00:00:00 2001 From: Bryan Barnes Date: Sun, 2 Feb 2014 21:40:18 -0500 Subject: [PATCH 19/19] Addressed review points -cleanup vmu that gets replaced by the mic -got rid of confusing old commented code -stopped big memory leak if mic data was not getting read but it was recording --- shell/android/jni/src/Android.cpp | 2 ++ .../src/com/reicast/emulator/SipEmulator.java | 18 ++---------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/shell/android/jni/src/Android.cpp b/shell/android/jni/src/Android.cpp index 115c6000d..93b6748af 100644 --- a/shell/android/jni/src/Android.cpp +++ b/shell/android/jni/src/Android.cpp @@ -14,6 +14,7 @@ #include "cfg/cfg.h" #include "rend/TexCache.h" #include "hw/maple/maple_devs.h" +#include "hw/maple/maple_if.h" #include "util.h" @@ -214,6 +215,7 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_JNIdc_setupMic(JNIEnv *env,jobj { sipemu = env->NewGlobalRef(sip); getmicdata = env->GetMethodID(env->GetObjectClass(sipemu),"getData","()[B"); + delete MapleDevices[0][1]; mcfg_Create(MDT_Microphone,0,1); } diff --git a/shell/android/src/com/reicast/emulator/SipEmulator.java b/shell/android/src/com/reicast/emulator/SipEmulator.java index 828fa4917..bb5afd88d 100644 --- a/shell/android/src/com/reicast/emulator/SipEmulator.java +++ b/shell/android/src/com/reicast/emulator/SipEmulator.java @@ -1,6 +1,5 @@ package com.reicast.emulator; -import java.util.LinkedList; import java.util.concurrent.ConcurrentLinkedQueue; import android.media.AudioFormat; @@ -37,7 +36,6 @@ public class SipEmulator extends Thread { init(); - } private void init(){ @@ -55,7 +53,6 @@ public class SipEmulator extends Thread { continueRecording = false; firstGet = true; } - public void startRecording(){ Log.d(TAG, "SipEmulator startRecording called"); @@ -97,26 +94,15 @@ public class SipEmulator extends Thread { public void run() { Log.d(TAG, "recordThread starting"); - //sleep to let some data come in - // try { - // Thread.sleep(TIME_TO_WAIT_BETWEEN_POLLS); - // } catch (InterruptedException e) { - // e.printStackTrace(); - // } while(continueRecording){ byte[] freshData = new byte[ONE_BLIP_SIZE]; // read blocks int bytesRead = record.read(freshData, 0, ONE_BLIP_SIZE); //Log.d(TAG, "recordThread recorded: "+bytesRead); - bytesReadBuffer.add(freshData); - /* - try { - Thread.sleep(TIME_TO_WAIT_BETWEEN_POLLS); - } catch (InterruptedException e) { - e.printStackTrace(); + if(!firstGet){ + bytesReadBuffer.add(freshData); } - */ } }