Cheap USB Skype/VoIP phone protocol discovery

usbphone

I’ve bought cheap USB handset from eBay to use with my VoIP provider. In Widows it worked good with supplied app which supported few VoIP programs and Skype. Since I use Linux on my desktop, I tried to plug it in. In USB listing it showed up as soundcard and HID device.

Bus 001 Device 008: ID 04b4:0307 Cypress Semiconductor Corp. 
Couldn't open device, some information will be missing
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x04b4 Cypress Semiconductor Corp.
  idProduct          0x0307 
  bcdDevice            1.10
  iManufacturer           0 
  iProduct                0 
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength          224
    bNumInterfaces          4
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           0
      bInterfaceClass         1 Audio
      bInterfaceSubClass      1 Control Device
      bInterfaceProtocol      0 
      iInterface              0 
      AudioControl Interface Descriptor:
        bLength                10
        bDescriptorType        36
        bDescriptorSubtype      1 (HEADER)
        bcdADC               1.00
        wTotalLength           79
        bInCollection           2
        baInterfaceNr( 0)       1
        baInterfaceNr( 1)       2
      AudioControl Interface Descriptor:
        bLength                12
        bDescriptorType        36
        bDescriptorSubtype      2 (INPUT_TERMINAL)
        bTerminalID             1
        wTerminalType      0x0101 USB Streaming
        bAssocTerminal          0
        bNrChannels             2
        wChannelConfig     0x0003
          Left Front (L)
          Right Front (R)
        iChannelNames           0 
        iTerminal               0 
      AudioControl Interface Descriptor:
        bLength                 9
        bDescriptorType        36
        bDescriptorSubtype      3 (OUTPUT_TERMINAL)
        bTerminalID             3
        wTerminalType      0x0301 Speaker
        bAssocTerminal          0
        bSourceID               2
        iTerminal               0 
      AudioControl Interface Descriptor:
        bLength                10
        bDescriptorType        36
        bDescriptorSubtype      6 (FEATURE_UNIT)
        bUnitID                 2
        bSourceID               1
        bControlSize            1
        bmaControls( 0)      0x03
          Mute Control
          Volume Control
        bmaControls( 1)      0x00
        bmaControls( 2)      0x00
        iFeature                0 
      AudioControl Interface Descriptor:
        bLength                12
        bDescriptorType        36
        bDescriptorSubtype      2 (INPUT_TERMINAL)
        bTerminalID             5
        wTerminalType      0x0201 Microphone
        bAssocTerminal          0
        bNrChannels             1
        wChannelConfig     0x0000
        iChannelNames           0 
        iTerminal               0 
      AudioControl Interface Descriptor:
        bLength                 9
        bDescriptorType        36
        bDescriptorSubtype      3 (OUTPUT_TERMINAL)
        bTerminalID             7
        wTerminalType      0x0101 USB Streaming
        bAssocTerminal          0
        bSourceID               6
        iTerminal               0 
      AudioControl Interface Descriptor:
        bLength                 8
        bDescriptorType        36
        bDescriptorSubtype      6 (FEATURE_UNIT)
        bUnitID                 6
        bSourceID               5
        bControlSize            1
        bmaControls( 0)      0x03
          Mute Control
          Volume Control
        iFeature                0 
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           0
      bInterfaceClass         1 Audio
      bInterfaceSubClass      2 Streaming
      bInterfaceProtocol      0 
      iInterface              0 
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       1
      bNumEndpoints           1
      bInterfaceClass         1 Audio
      bInterfaceSubClass      2 Streaming
      bInterfaceProtocol      0 
      iInterface              0 
      AudioStreaming Interface Descriptor:
        bLength                 7
        bDescriptorType        36
        bDescriptorSubtype      1 (AS_GENERAL)
        bTerminalLink           1
        bDelay                  1 frames
        wFormatTag              1 PCM
      AudioStreaming Interface Descriptor:
        bLength                11
        bDescriptorType        36
        bDescriptorSubtype      2 (FORMAT_TYPE)
        bFormatType             1 (FORMAT_TYPE_I)
        bNrChannels             2
        bSubframeSize           2
        bBitResolution         16
        bSamFreqType            1 Discrete
        tSamFreq[ 0]        48000
      Endpoint Descriptor:
        bLength                 9
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            9
          Transfer Type            Isochronous
          Synch Type               Adaptive
          Usage Type               Data
        wMaxPacketSize     0x00c0  1x 192 bytes
        bInterval               1
        bRefresh                0
        bSynchAddress           0
        AudioControl Endpoint Descriptor:
          bLength                 7
          bDescriptorType        37
          bDescriptorSubtype      1 (EP_GENERAL)
          bmAttributes         0x00
          bLockDelayUnits         0 Undefined
          wLockDelay              0 Undefined
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        2
      bAlternateSetting       0
      bNumEndpoints           0
      bInterfaceClass         1 Audio
      bInterfaceSubClass      2 Streaming
      bInterfaceProtocol      0 
      iInterface              0 
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        2
      bAlternateSetting       1
      bNumEndpoints           1
      bInterfaceClass         1 Audio
      bInterfaceSubClass      2 Streaming
      bInterfaceProtocol      0 
      iInterface              0 
      AudioStreaming Interface Descriptor:
        bLength                 7
        bDescriptorType        36
        bDescriptorSubtype      1 (AS_GENERAL)
        bTerminalLink           7
        bDelay                  1 frames
        wFormatTag              1 PCM
      AudioStreaming Interface Descriptor:
        bLength                11
        bDescriptorType        36
        bDescriptorSubtype      2 (FORMAT_TYPE)
        bFormatType             1 (FORMAT_TYPE_I)
        bNrChannels             1
        bSubframeSize           2
        bBitResolution         16
        bSamFreqType            1 Discrete
        tSamFreq[ 0]         8000
      Endpoint Descriptor:
        bLength                 9
        bDescriptorType         5
        bEndpointAddress     0x83  EP 3 IN
        bmAttributes            1
          Transfer Type            Isochronous
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0010  1x 16 bytes
        bInterval               1
        bRefresh                0
        bSynchAddress           0
        AudioControl Endpoint Descriptor:
          bLength                 7
          bDescriptorType        37
          bDescriptorSubtype      1 (EP_GENERAL)
          bmAttributes         0x00
          bLockDelayUnits         0 Undefined
          wLockDelay              0 Undefined
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        3
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 No Subclass
      bInterfaceProtocol      0 None
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.10
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      36
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval              48
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x04  EP 4 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0020  1x 32 bytes
        bInterval               1


Soundcard was working out of box: headset speaker and mic were correctly working when set in my linphone SIP client. But I also wanted to utilize phones keyboard and display. I checked which /dev/hidrawX device corresponds to my phone and started
sudo cat /dev/hidraw1 | hexdump. When I pressed buttons, following output has appeared:

#sudo cat /dev/hidraw1 | hexdump 
0000000 0301 0100 0101 0101 0001 0100 0101 0101
0000010 0901 0100 0101 0101 0001 0100 0101 0101
0000020 0f01 0100 0101 0101 0001 0100 0101 0101
0000030 0401 0100 0101 0101 0001 0100 0101 0101
0000040 0a01 0100 0101 0101 0001 0100 0101 0101
0000050 1001 0100 0101 0101 0001 0100 0101 0101
0000060 0501 0100 0101 0101 0001 0100 0101 0101
0000070 0b01 0100 0101 0101 0001 0100 0101 0101
0000080 1101 0100 0101 0101 0001 0100 0101 0101

Good! One line for each button press. So I created a short python script to open /dev/hidraw1, read inputs, then map it to keys and print to stdout and it worked great!

#!/usr/bin/python

keys = {
  0x00 : "",
  0x03 : "1",
  0x09 : "2",
  0x0f : "3",
  0x04 : "4",
  0x0a : "5",
  0x10 : "6",
  0x05 : "7",
  0x0b : "8",
  0x11 : "9",
  0x06 : "*",
  0x0c : "0",
  0x12 : "#",
  0x02 : "yes",
  0x08 : "S",
  0x0e : "no",
  0x01 : "left",
  0x13 : "up",
  0x16 : "down",
  0x0d : "right",
  0x19 : "vol+",
  0x1c : "vol-",
  0x1b : "mute",
}

file = open( "/dev/hidraw1", "w+b" );

def getKey():
  buf = file.read(8)
  return keys[ord(buf[1])]

while( 1 ):
  k = getKey();
  print k

file.close();

Next mission was to make the display work. My assumption was, that it will also communicate through hidraw device. So I fired dd if=/dev/urandom of=/dev/hidraw1 and YES! Time to time the display blinked or showed some messy pixel block.

IMG_20141102_132940

So I returned back to windows. I fired up usbsnoop to see what does the original software send to update screen. I found out, that it sends many blocks in form:
0x0301XXYYZZZZZZZZZZZZZZZZZZZZZZX’s and Y’s were incrementing independently and Z’s were apparently some data. I experimented with sending 0x0301XXYYFFFFFFFFFFFFFFFFFFFFFF with various X’s and Y’s like this:

      buf="0301".decode("hex")+chr(x)+chr(y)+"ffffffffffffffffffffff".decode("hex")
      file.write(buf)

Some of them were written to display as full black blocks and some were not. I spent some time experimenting what’s wrong after I found out, that I have to file.flush() after writing each block.

Afer this, I was able to successfully write any block on the screen. In following code you can check exactly how.

#!/usr/bin/python

import struct
import Image, ImageDraw, ImageFont
import time

keys = {
  0x00 : "",
  0x03 : "1",
  0x09 : "2",
  0x0f : "3",
  0x04 : "4",
  0x0a : "5",
  0x10 : "6",
  0x05 : "7",
  0x0b : "8",
  0x11 : "9",
  0x06 : "*",
  0x0c : "0",
  0x12 : "#",
  0x02 : "yes",
  0x08 : "S",
  0x0e : "no",
  0x01 : "left",
  0x13 : "up",
  0x16 : "down",
  0x0d : "right",
  0x19 : "vol+",
  0x1c : "vol-",
  0x1b : "mute",
}

file = open( "/dev/hidraw1", "w+b" );

def getKey():
  buf = file.read(8)
  return keys[ord(buf[1])]

def paint():
  pixels = img.load() # create the pixel map
  pixels = img.transpose(Image.ROTATE_180).load() # create the pixel map
  b = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  for r in range(0, 8):
    for s in range (0, 12):
      for i in range (0, 12):
	b[i] = 0
	for j in range (0, 8):
          if (pixels[i + 12 * s, j + 8 * r] < 128):
	    b[i] |= 2**j
      buf="0301".decode("hex")+chr(r)+chr(s*11)+chr(b[0])+chr(b[1])+chr(b[2])+chr(b[3])+chr(b[4])+chr(b[5])+chr(b[6])+chr(b[7])+chr(b[8])+chr(b[9])+chr(b[10])+chr(b[11])
      file.write(buf)
      file.flush()

def drawText(text):
  draw.text((0, 0), drawText.old , 255, font=font)
  draw.text((0, 0), text , 0, font=font)
  drawText.old = text
  paint()

drawText.old = ""
img = Image.new( '1', (144,64), "white")
draw = ImageDraw.Draw(img)

font = ImageFont.truetype("/usr/share/fonts/truetype/msttcorefonts/arial.ttf", 20)
text = ""

# draw logo into canvas
logo = Image.open("logo.png").convert("1")
img.paste(logo, (0,0))

# write canvas to display
paint()

# clear canvas
draw.rectangle((0,0,142,63), fill=255)

while( 1 ):
  k = getKey();
  if (k == ""):
    0
  elif (k == "no"):
    text = ""
    drawText(text)
  elif (k == "yes"):
    text = ""
    drawText("calling...")
  else:
    text = text + k
    drawText(text)
#    img.show()

file.close();

Note: Displays first pixel is in the lower right corner, so when displaying things, you have to rotate image 180°.

I know that all this can possibly be found in phones chip documentation but this way it was definitely more fun.

Meanwhile I stopped using VoIP services so my motivation to integrate this with some VoIP phone is gone :). Feel free to finish this and share.

To end up, I attach some photos.

IMG_20140329_161609IMG_20141102_142236 IMG_20141102_141734

9 thoughts on “Cheap USB Skype/VoIP phone protocol discovery

  1. Pingback: Discovering the Protocol in a USB VoIP Phone

  2. Pingback: Discovering the Protocol in a USB VoIP Phone - Tech key | Techzone | Tech data

  3. Pingback: Discovering the Protocol in a USB VoIP Phone | Ad Pub

  4. Pingback: Discovering the Protocol in a USB VoIP Phone - Arduino collector blog

  5. Pingback: Discovering the Protocol in a USB VoIP Phone | 0-HACK

  6. Pingback: USB switch for 2 PC under Linux | danmans blog

Leave a Reply

Your email address will not be published. Required fields are marked *