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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 37 additions & 18 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 PulseaudioSBCStream


class DS4Controller(object):
def __init__(self, index, options, dynamic=False):
def __init__(self, index, options, sbc_stream, 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.sbc_stream = sbc_stream

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, sbc_stream,
dynamic=False):
controller = DS4Controller(index, controller_options, sbc_stream,
dynamic=dynamic)

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


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

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

def cleanup_sbc_stream(self):
self.sbc_stream.stop()

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

self.cleanup_controller_threads()
self.cleanup_sbc_stream()
self.cleanup_controller_controller_threads()

sys.exit(0)


def main():
threads = []
sbc_stream = PulseaudioSBCStream(
"ds4drv", "Test ds4drv sink"
)
sbc_stream.run()

controller_threads = []

sigint_handler = SigintHandler(threads)
sigint_handler = SigintHandler(controller_threads, sbc_stream)
signal.signal(signal.SIGINT, sigint_handler)

try:
Expand All @@ -172,35 +188,38 @@ 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)
threads.append(thread)
thread = create_controller_thread(
index + 1, controller_options, sbc_stream
)
controller_threads.append(thread)

for device in backend.devices:
connected_devices = []
for thread in threads:
for thread in controller_threads:
# Controller has received a fatal error, exit
if thread.controller.error:
sys.exit(1)

if thread.controller.device:
connected_devices.append(thread.controller.device.device_addr)

# Clean up dynamic threads
# Clean up dynamic controller_threads
if not thread.is_alive():
threads.remove(thread)
controller_threads.remove(thread)

if device.device_addr in connected_devices:
backend.logger.warning("Ignoring already connected device: {0}",
device.device_addr)
continue

for thread in filter(lambda t: not t.controller.device, threads):
for thread in filter(lambda t: not t.controller.device, controller_threads):
break
else:
thread = create_controller_thread(len(threads) + 1,
thread = create_controller_thread(len(controller_threads) + 1,
options.default_controller,
sbc_stream,
dynamic=True)
threads.append(thread)
controller_threads.append(thread)

thread.controller.setup_device(device)

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
43 changes: 43 additions & 0 deletions ds4drv/actions/audio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from ..action import Action
from ..audio import SBCHeaders
from ..audio import pulseaudio_sbc_stream

import os

class AudioAction(Action):
"""Plays audio through the device"""

def setup(self, device):
self.sbc_stream = self.controller.sbc_stream
self.loop = self.controller.loop

self.read_pipe, self.write_pipe = os.pipe()

self.sbc_stream.add_fd(self.write_pipe)

self.loop.add_watcher(self.read_pipe, self.play_audio)


def disable(self):
self.sbc_stream.remove_fd(self.write_pipe)


def play_audio(self):
if not self.controller.device:
return

# Read the SBC header
frame_header = os.read(self.read_pipe, 10)

# Parse and find the length of the frame
sbc_header = SBCHeaders()
sbc_header.parse_header(frame_header)
sbc_len = sbc_header.calculate_frame_length()

# Read the rese of the frame
rest_of_frame = os.read(self.read_pipe, sbc_len - 10)

sbc_frame = frame_header + rest_of_frame

# Call play_audio
self.controller.device.play_audio(sbc_header, sbc_frame)
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 .pulseaudio_sbc_stream import PulseaudioSBCStream
Loading