Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic audio working. Many kinks. #80

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
35 changes: 29 additions & 6 deletions ds4drv/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
from .daemon import Daemon
from .eventloop import EventLoop
from .exceptions import BackendError
from .audio import GstPulseToSBCPipeline


class DS4Controller(object):
def __init__(self, index, options, dynamic=False):
def __init__(self, index, options, audio_pipeline, dynamic=False):
self.index = index
self.dynamic = dynamic
self.logger = Daemon.logger.new_module("controller {0}".format(index))
Expand All @@ -33,6 +34,8 @@ def __init__(self, index, options, dynamic=False):
if self.profiles:
self.profiles.append("default")

self.audio_pipeline = audio_pipeline

self.load_options(self.options)

def fire_event(self, event, *args):
Expand Down Expand Up @@ -120,8 +123,10 @@ def exit(self, *args, error = True):
self.logger.info(*args)


def create_controller_thread(index, controller_options, dynamic=False):
controller = DS4Controller(index, controller_options, dynamic=dynamic)
def create_controller_thread(index, controller_options, audio_pipeline,
dynamic=False):
controller = DS4Controller(index, controller_options, audio_pipeline,
dynamic=dynamic)

thread = Thread(target=controller.run)
thread.controller = controller
Expand All @@ -131,26 +136,33 @@ def create_controller_thread(index, controller_options, dynamic=False):


class SigintHandler(object):
def __init__(self, threads):
def __init__(self, threads, audio_pipeline):
self.threads = threads
self.audio_pipeline = audio_pipeline

def cleanup_controller_threads(self):
for thread in self.threads:
thread.controller.exit("Cleaning up...", error=False)
thread.controller.loop.stop()
thread.join()

def cleanup_audio_pipeline(self):
self.audio_pipeline.stop()

def __call__(self, signum, frame):
signal.signal(signum, signal.SIG_DFL)

self.cleanup_audio_pipeline()
self.cleanup_controller_threads()

sys.exit(0)


def main():
threads = []
audio_pipeline = GstPulseToSBCPipeline()

sigint_handler = SigintHandler(threads)
sigint_handler = SigintHandler(threads, audio_pipeline)
signal.signal(signal.SIGINT, sigint_handler)

try:
Expand All @@ -172,10 +184,20 @@ def main():
Daemon.fork(options.daemon_log, options.daemon_pid)

for index, controller_options in enumerate(options.controllers):
thread = create_controller_thread(index + 1, controller_options)
thread = create_controller_thread(
index + 1, controller_options, audio_pipeline
)
threads.append(thread)

audio_pipeline.start()

for device in backend.devices:
print("-----")
from multiprocessing import Pool
p = Pool(processes=1)
def f(d):
print("f:", d)
p.apply_async(f, (device,))
connected_devices = []
for thread in threads:
# Controller has received a fatal error, exit
Expand All @@ -199,6 +221,7 @@ def main():
else:
thread = create_controller_thread(len(threads) + 1,
options.default_controller,
audio_pipeline,
dynamic=True)
threads.append(thread)

Expand Down
1 change: 1 addition & 0 deletions ds4drv/actions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
from . import input
from . import led
from . import status
from . import audio
128 changes: 128 additions & 0 deletions ds4drv/actions/audio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
from ..action import Action
from ..audio import SBCHeaders


class AudioCallbacks():
callbacks = []

def __call__(self, buffer, data):
import os
#print("cbpid: ", os.getpid())
for callback in self.callbacks:
callback(data)

import os
from io import FileIO
hidraw_device = "/dev/hidraw3"
report_fd = os.open(hidraw_device, os.O_RDWR | os.O_NONBLOCK)
fd = FileIO(report_fd, "rb+", closefd=False)
class AudioAction(Action):
"""Plays audio through the device"""

frame_number = 0
audio_buffer = b''

def setup(self, device):
self.audio_pipeline = self.controller.audio_pipeline

if not isinstance(self.audio_pipeline.get_callback(), AudioCallbacks):
self.audio_pipeline.set_callback(AudioCallbacks())

self.audio_pipeline.get_callback().callbacks.append(self.play_audio)

self.audio_pipeline.restart()

def play_audio(self, data):
pos = 0
sbc_headers = SBCHeaders()

#print()
#print("ld: ", len(data))
import os
#print("lpid:", os.getpid())
while pos != len(data):
sbc_headers.parse_header(data)
frame_length = sbc_headers.calculate_frame_length()
#print("fl: ", frame_length)

self.controller.device.play_audio(sbc_headers,
data[pos:pos + frame_length])
#self.lplay_audio(None, data[pos:(pos+frame_length)])

pos += frame_length
#print("done")

def lplay_audio(self, sbc_headers, data):
print()
print(len(self.audio_buffer))
print(len(data))
print()
if len(self.audio_buffer) + len(data) <= 448:
self.audio_buffer += data
return
print("running: ", len(self.audio_buffer))

rumble_weak = 0
rumble_strong = 0
r = 0
g = 0
b = 10
crc = b'\x00\x00\x00\x00'
volume_speaker = 80
volume_l = 60
volume_r = 60
unk2 = 100
unk3 = 100
flash_bright = 0
flash_dark = 0
#audio_header = b'\x24'
audio_header = b'\x24'


def frame_number(inc):
import struct
res = struct.pack("<H", self.frame_number)
self.frame_number += inc
if self.frame_number > 0xffff:
self.frame_number = 0
return res

def joy_data():
data = [0xff,0x4,0x00]
#global volume_r,volume_unk2, unk3
data.extend([rumble_weak,rumble_strong,r,g,b,flash_bright,flash_dark])
data.extend([0]*8)
data.extend([volume_l,volume_r,unk2,volume_speaker,unk3])
return data


def _11_report():
data = joy_data()
data.extend([0]*(48))
return b'\x11\xC0\x20' + bytearray(data) + crc

try:
if self.reported_11 == True: pass
except AttributeError:
fd.write(_11_report())

def _17_report(audo_data):
return (
b'\x17\x40\xA0'
+ frame_number(4)
+ audio_header
+ audo_data
+ bytearray(452 - len(audo_data)) + crc
)
report = _17_report(self.audio_buffer)

print(data[0])
self.audio_buffer = data

#if self._volume_r == 0:
# self.set_volume(60, 60, 0)
# self._control()
#self.write_report(report[0], report[1:])
print(report)
print(len(report))
fd.write(report)
2 changes: 2 additions & 0 deletions ds4drv/audio/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .sbc_headers import SBCHeaders
from .gst_pulse_to_sbc_pipeline import GstPulseToSBCPipeline
Loading