xemu-project / xemu

Original Xbox Emulator for Windows, macOS, and Linux (Active Development)
https://xemu.app
Other
2.83k stars 283 forks source link

Add Xbox Live Communicator Support #1126

Open Ryzee119 opened 2 years ago

Ryzee119 commented 2 years ago

Feature Request

Xbox Live Communicator (XBLC) is a a usb1.1 compliant device with two interfaces. One for Microphone and one for a mono speaker.

The usb device descriptor has previously been recorded here: https://xboxdevwiki.net/Xbox_Live_Communicator.

The speaker and microphone interface each has a single isochronous endpoint. Its unclear how the Xbox identifies the XBLC. It could either be by hardcoded PID/VIDs (unlikely), or more likely the bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol specifiers in the interface descriptors (this is how all other xbox peripherals are identified). The speaker and mic are likely differentiated by the direction of the isochronous endpoint, but could also be the interface index (unlikely though)

The headset supports the following audio sample rates (All at signed 16bit LE PCM samples). The units are in samples per second. As far as I can tell, the microphone and speaker always have the same sample rate:

For example at 24000 samples/sec, each USB frame (1000hz) sends 24x16bit samples which corresponds to 48bytes per USB frame which lines up with the Max packet size indicated in the interface descriptor.

If a sample rate does not divide evenly into USB frame 1ms blocks, the Xbox will add an additional sample every n frames. The formula for calculating this is 1000 / (sample_rate % 1000) = n, where % is the modulo operator.. For example at 11025 kHz, XDK will add an extra sample every 40 USB frames.

The sample rate is set by a control transfer to endpoint 0 of the device.

The control transfer for setting the sample rate has the following format (Ref usb2 spec 9.3)

bmRequestType = Host-to-device | Vendor | Interface (0x41)
bRequest = SET_FEATURE (0x03)
wValue = 0x100 | sample_rate
wIndex = 0x0000
wLength = 0x0000

Where sample_rate = 0 for 8000, up to 4 for 24000.

It is also not clear if the game can change this sample rate at any time, all games I tested only did it once after connection. Doing some testing in nxdk seemed to caused garbled audio if I attempted to change it a second time but this could be a bug elsewhere.

There is also a secondary control transfer that can occur. It is not exacty clear on its purpose, however I believe it is to do with Auto gain control for the micrphone. Ref https://web.archive.org/web/20200521011406/http://www.kako.com/neta/2005-009/uac3556b.pdf, Section 3.2

It has the following format:

bmRequestType = Host-to-device | Vendor | Interface (0x41)
bRequest = SET_FEATURE (0x03)
wValue = 0x0001 or 0x0000 (enable or disable?)
wIndex = 0x0001
wLength = 0x0000

Where wValue = 0 or 1 to enable or disable this feature

I have not observed any other usb transfers to the device.

I have written a functioning nxdk driver here https://github.com/Ryzee119/nxdk/blob/xblc/lib/usb/libusbohci_xbox/xblc_driver.c fo ref.

I can work on this, and will communicate progress here.

Alternatives

No response

Additional Context

No response

mborgerson commented 2 years ago

Related #389

Ryzee119 commented 2 years ago

One initial hurdle is that upstream qemu says it does not support isochronous endpoints on its OHCI backend https://github.com/qemu/qemu/blob/5c8463886d50eeb0337bd121ab877cf692731e36/hw/usb/hcd-ohci.c#L21

Although its not clear whats working or not.

And ofcourse we need a way of linking user's audio devices into the XBLC backend and a corresponding GUI element.

Ryzee119 commented 2 years ago

The communicator is physically keyed so that it only fits on the front port. This represents port number 2 of the internal controller's hub.

I tested this by emulating it in the other port but the device will not function properly atleast in XDK based games.

Ryzee119 commented 2 years ago

I have a mostly working xblc driver here: https://github.com/Ryzee119/xemu/blob/xblc1/hw/xbox/xblc.c Still a couple issues with scheduling iso packets. Unclear why this is occuring as the USB frame counter is synced with the rest of the emulation. Its getting caught up in here and seems to never be able to recover properly. Could be a bug in OHCI or even XDK?

https://github.com/mborgerson/xemu/blob/30042e809152b6c069611f13ab8e57739ebf4a16/hw/usb/hcd-ohci.c#L689-L697

For windows we also need to remove this: https://github.com/mborgerson/xemu/blob/9c06980275b6b31fc9f1b7f7df9ac692dad508d8/softmmu/vl.c#L2969-L2973

Perhaps we need to move to a SDL audio driver backend?

It will just take the default microphone input set by your PC. The audio output is mixed into your default audio out.