16.04 블루투스 A2DP 헤드폰을 사용할 수 없지만 페어링되지는 않습니다. 내부 로그


15

우선, 나는 다음 두 가지를 모두 시도했습니다 : https://vilimpoc.org/blog/2016/04/30/ubuntu-16-04-bluetooth-speakers/PulseAudio는 블루투스 모듈 15.10 / 16.04 / 16.10을로드 할 수 없습니다

Jaybird X2 (데스크톱 및 랩톱, Broadcom 및 인텔 모두에서 시도)를 연결하려고하면 2 초 동안 연결 한 다음 연결이 끊어집니다.

syslog 양식 기록 (widecom BT가있는 데스크탑에서)

May 31 23:50:54 desktop pulseaudio[6247]: [pulseaudio] socket-server.c: bind(): Address already in use
May 31 23:50:54 desktop pulseaudio[6247]: [pulseaudio] module.c: Failed to load module "module-cli-protocol-unix" (argument: ""): initialization failed.
May 31 23:50:54 desktop pulseaudio[6247]: [pulseaudio] socket-server.c: bind(): Address already in use
May 31 23:50:54 desktop pulseaudio[6247]: [pulseaudio] module.c: Failed to load module "module-cli-protocol-unix" (argument: ""): initialization failed.

그리고 다른 시간 :

a2dp-sink profile connect failed for xxxxxxx Protocol not available

편집 .. 중요 :

이제 다른 장치에 연결하려고하면 대부분 잘 작동합니다 (Micropod BT 및 Samsung AirTrack). 그러나 Jaybird X2를 사용 하자마자 모듈-블루투스 감지를 비활성화 / 언로드pactl load-module module-bluetooth-discover 합니다. 다른 두 개는 다시 작동합니다 ..

이제 이것은 노트북에서 발생합니다.

May 31 17:02:58 vooze-x1 pulseaudio[3534]: [pulseaudio] backend-native.c: connect(): Function not implemented
May 31 17:02:58 vooze-x1 pulseaudio[3534]: [pulseaudio] volume.c: Assertion 'pa_channels_valid(channels)' failed at pulse/volume.c:74, function pa_cvolume_set(). Aborting.
May 31 17:02:58 vooze-x1 bluetoothd[865]: Endpoint unregistered: sender=:1.130 path=/MediaEndpoint/A2DPSource
May 31 17:02:58 vooze-x1 bluetoothd[865]: Endpoint unregistered: sender=:1.130 path=/MediaEndpoint/A2DPSink
May 31 17:03:00 vooze-x1 pulseaudio[3764]: [pulseaudio] main.c: User-configured server at {ddcf951d58914c47b9adca0056c50142}unix:/run/user/1000/pulse/native, which appears to be local. Probing deeper.
May 31 17:03:00 vooze-x1 pulseaudio[3767]: [pulseaudio] pid.c: Stale PID file, overwriting.

이전에 데스크톱에서 간단히 연결할 수 있었지만 A2DP는 대부분 작동하지 않았습니다.

서로 다른 두 가지 오류가 있지만 동일한 문제 무슨 일이야?

우분투 16.04에서 블루투스가 고장 났습니까? 그것은 Windows와 내 안드로이드 폰에서 작동합니다.

어떤 도움이라도 좋을 것입니다! :) 어떻게 든 간단하게 작동 시켜서 처음에는 효과가 있었고 A2DP는 작동하지 않았습니다. 그래서 이것이 A2DP와 관련이 있다고 생각합니다. 확실하지 않다.


연결하기 전에 헤드셋을 페어링 모드로 설정 했습니까? 꺼진 장치에서 빨간색 / 녹색 깜박임이 켜질 때까지 가운데 키를 4 초 동안 누르십시오. 우분투에서 검색하고 연결하십시오. askubuntu.com/questions/259354/…
Takkat

그렇습니다. 문제는 페어링이 아니라 "연결 중"입니다. 연결되고 "헤드폰 연결됨"이라고 말한 후 2 초 후에 연결이 끊어집니다.
Joakim Koed

제대로 페어링 된 장치가 연결되지 않은 것처럼 보이지만 실패하는 증상이므로 묻습니다. (알려진 장치에서 장치를 제거한 후) 다시 시도하는 것이 좋습니다.
Takkat

Takket : 아마 20 번 했어요. 하드 리셋 헤드셋 등
Joakim Koed

1
버그 @RobertIanHawdon을 제출해 주셔서 감사합니다. 본인은 영향을받은 것으로 표시했습니다.
Joakim Koed 2016 년

답변:


12

알려진 버그입니다. 시도하십시오 rmmod btusb ; modprobe btusb. 나는 그것을 4 번까지해야했다.

Intel 8260 wifi / bluetooth가 장착 된 Lenovo P50에서이를 확인했습니다. 때때로 부팅시 블루투스 펌웨어가 올바르게로드되지 않습니다. 다른 경우에는 작동하지 않습니다.


2
16.04에 대한 Bluetooth 지원에서 심각한 회귀가있었습니다.
Amias

@Amias 글쎄, 14.04에서 블루투스를 사용할 수 없었습니다.
jarno

1
16.04를 실행하는 Lenovo Y510P에서 작동합니다. ~ / .bashrc에 별명을 추가했습니다 :alias headphones='sudo rmmod btusb ; sudo modprobe btusb'
BenB

3

다른 Bluetooth 오디오 장치가 문제없이 작동했지만 Jaybird X2 및 Bluebuds X와 동일한 문제가있었습니다. 헤드폰으로 다음과 같은 오류가 발생했습니다.

Assertion 'pa_channels_valid(channels)' failed at pulse/volume.c:74, function pa_cvolume_set(). Aborting.

펄스 오디오가 추락했습니다. 그것을 해결 한 것은 소스에서 펄스 오디오를 설치하는 것이 었습니다.

  • 필요한 모든 패키지를 설치하십시오. sudo apt-get build-dep pulseaudio
  • https://freedesktop.org/software/pulseaudio/releases/pulseaudio-9.0.tar.gz를 다운로드 하고 압축을 풉니 다.
  • 소스 디렉토리에서 다음을 실행하십시오 ./bootstrap.sh --prefix=/usr.. 원하는 경우 CFLAGS컴파일러 최적화를 사용 하도록 변수를 변경할 수 있습니다 ( 예 : -O2대신 사용) -O0.
  • 그런 다음, makesudo make install

기본 시스템 설치를 덮어 쓰지만 패키지가 업데이트 될 때까지 작동합니다. 업데이트를 방지하기 위해 pulseaudio 패키지를 보류시킬 수 있습니다.

sudo apt-mark hold libpulse-dev libpulse0 libpulse-mainloop-glib0 pulseaudio pulseaudio-module-bluetooth pulseaudio-utils libpulsedsp pulseaudio-module-x11

참고 내가 펄스 오디오 9.0을 설치했지만 작동 만든 버전이 아닌 것을. PPA 에서 패키지 버전의 pulseaudio 9.0을 사용해 보았지만 동일한 오류가 발생했습니다.


안녕하세요. 그것이 모든 디케이 시도 컴파일합니까? 나는 실제로 어제 wily에서 6으로 다운 그레이드했습니다. 완벽하게 작동했습니다.
Joakim Koed

컴파일에 문제가 없었습니다. 무슨 소리 야?
Andrzej Pronobis

버전이 아닌 경우 차이점은 무엇입니까?
Daniel Szmulewicz

2

Bluedio T + 3 헤드셋에서이 문제가 발생했으며 연결 시간이 초과되었다고 생각합니다. 세미콜론 (;)을 제거하여 ; exit-idle-time = 20파일 에서 행의 주석을 해제해야합니다 /etc/pulse/daemon.conf.

값을 다음 -1과 같이 변경하십시오 .

exit-idle-time = -1

그런 다음 bluetoothctl다시 사용 하여 장치에 연결하십시오. 지침은 여기를 참조하십시오.

아치 위키 : 블루투스 헤드셋


1

다음을 확인하십시오.

  • Jaybird X2가 페어링되었습니다
  • 신뢰할 수있는 것으로 표시됩니다 (via bluetoothctltrust XX:XX:XX:XX(여기서 XX:XX:XX:XXJaybird의 MAC 주소) 또는를 통해 blueman-manager)
  • 켜져있다

Jaybird X2의 전원 버튼을 한 번 누르십시오. 이것은 알려진 장치에 대한 자동 연결을 트리거합니다. 따라서 다른 장치가 여기에 방해가되지 않도록해야합니다. 그때부터 연결이 안정적이었고 재부팅 후 자동으로 연결됩니다.

이 방법으로도 문제가 해결되었는지 알려주십시오. 나는 실수로 전원 버튼을 눌렀을 때 다른 일을 많이하고 거의 포기했습니다. ;-) 그래서 다른 것들 중 하나가 문제를 해결했을 수도 있습니다. (이미 블루투스, pulseaudio, bluez, pactl load-module 주위에서 이미 검색하고 시도하고 있었으므로 여전히 많은 힌트가 있습니다 :-D)

업데이트 (연결 문제가 다시 발생한 후)

Jaybird X2를 안드로이드 폰에 연결 한 후, 안드로이드 폰에서 연결을 끊은 후에도 랩톱에 다시 연결할 수 없었습니다. 아직 문제가 무엇인지 모르지만 연결을 다시 얻으려면 다음을 수행해야했습니다.

  1. 내 안드로이드 폰 (또는 다른 기기)에서 Jaybird X2 연결 해제
  2. 우분투 재부팅
  3. 다시 연결이 작동하고 연결이 안정적입니다 (일반적으로 처음 페어링 할 때 작동하지 않았습니다 ... 그 후에도 재부팅해야 함)

나는 또한 다른 것들을 시도했고 적어도 pulseaudio-module-bluetooth요구되는 것처럼 보입니다 . 또한 wifi / bluetooth 공존 구성은 적어도 내 컴퓨터에 필요합니다 ( /ubuntu//a/645072/558838 참조 ). 그리고 마지막으로 : 다른 장치로 전환 한 경우 항상 연결을 다시 시작하려면 재부팅해야합니다.

요약하면, 재부팅 단계를 통해 Jaybird X2를 성공적으로 다시 연결할 수 있으며 연결이 안정적입니다. 누구든지 재부팅 단계를 생략하는 더 쉬운 방법을 알고 있다면 /etc/init.d/bluetooth restart충분합니다 :) 기여 하지 마십시오.

(내가 시도한 추가 단계) :

나는 내 역사를 조사했다. 또한 하나 또는 다른 하나가 위의 솔루션에 기여했을 수있는 다음을 시도했습니다.

  • apt-get install pulseaudio-module-bluetooth (내 시스템에는 설치되지 않았습니다)
  • 로그는 missing ofono에 대해 언급 했으므로 설치했습니다.
  • 했다 sudo chown -R $USER ~/*
  • 또한 적용 : /ubuntu//a/691299/558838 (그러나 도움이되지 않아 되돌 렸지만 자동 연결을 시도했을 때 여전히 활성화되었을 수 있습니다)
  • 또한 pulseaudio, blueman, bluetooth packag를 제거 / 설치했습니다

내가 시도하자마자 그냥 시험 해보고 충돌을 도와 주셔서 감사합니다. 나는 다음 시도 : pactl로드 모듈 모듈 블루투스는-발견 한 후 전원 버튼을 눌러 다시, 다시 한번 펄스 오디오 추락 : /
조아킴 Koed

시도한 답변에 추가 단계를 추가했습니다. 어떤 것에 대한 세부 정보가 필요하면 물어보십시오.
Roland

확인. 오늘 다른 것을 발견했습니다 : 수면 후 나는 다시 작동하지 못했습니다. 여전히 재부팅 후 작동합니다. 더 나쁜 것은 : 블루투스 연결이 설정되면 내 무선 연결이 더 이상 작동하지 않습니다. 연결되어 있지만 아무것도 전송하지 않습니다. 그 중 하나를 더 조사해야합니다.
Roland

자신을 영향을받은 것으로 표시하십시오 : bugs.launchpad.net/ubuntu/+source/pulseaudio/+bug/1574324
Joakim Koed 2016 년

askubuntu.com/a/645072/558838 :) wifi / bluetooth 공존 문제를 다음과 같이 수정 했습니다. 그것은 지금 작동 ... 어쩌면 공존 버그도 안정적인 연결에 대한 문제입니까? 적어도 내가 나열된 다른 것보다 더 합리적으로 들립니다 :-) 저것도 시도 할 수 있습니까?
Roland

1

GitHub에서 스크립트를 실행하십시오 .

그리고 문제는 사라질 것입니다.

#! /usr/bin/env python3.5
"""

Fixing bluetooth stereo headphone/headset problem in ubuntu 16.04 and also debian jessie, with bluez5.

Workaround for bug: https://bugs.launchpad.net/ubuntu/+source/indicator-sound/+bug/1577197
Run it with python3.5 or higher after pairing/connecting the bluetooth stereo headphone.

This will be only fixes the bluez5 problem mentioned above .

Licence: Freeware

See ``python3.5 a2dp.py -h``.

Shorthands:

    $ alias speakers="a2dp.py 10:08:C1:44:AE:BC"
    $ alias headphones="a2dp.py 00:22:37:3D:DA:50"
    $ alias headset="a2dp.py 00:22:37:F8:A0:77 -p hsp"

    $ speakers



Check here for the latest updates: https://gist.github.com/pylover/d68be364adac5f946887b85e6ed6e7ae

Thanks to:

 * https://github.com/DominicWatson, for adding the ``-p/--profile`` argument.
 * https://github.com/IzzySoft, for mentioning wait before connecting again.
 * https://github.com/AmploDev, for v0.4.0

Change Log
----------

- 0.4.1
  * Sorting device list

- 0.4.0
  * Adding ignore_fail argument by @AmploDev.
  * Sending all available streams into selected sink, after successfull connection by @AmploDev.

- 0.3.3
  * Updating default sink before turning to ``off`` profile.

- 0.3.2
  * Waiting a bit: ``-w/--wait`` before connecting again.

- 0.3.0
  * Adding -p / --profile option for using the same script to switch between headset and A2DP audio profiles

- 0.2.5
  * Mentioning [mac] argument.

- 0.2.4
  * Removing duplicated devices in select device list.

- 0.2.3
  * Matching ANSI escape characters. Tested on 16.10 & 16.04

- 0.2.2
  * Some sort of code enhancements.

- 0.2.0
  * Adding `-V/--version`, `-w/--wait` and `-t/--tries` CLI arguments.

- 0.1.1
  * Supporting the `[NEW]` prefix for devices & controllers as advised by @wdullaer
  * Drying the code.

"""

import sys
import re
import asyncio
import subprocess as sb
import argparse


__version__ = '0.4.0'


HEX_DIGIT_PATTERN = '[0-9A-F]'
HEX_BYTE_PATTERN = '%s{2}' % HEX_DIGIT_PATTERN
MAC_ADDRESS_PATTERN = ':'.join((HEX_BYTE_PATTERN, ) * 6)
DEVICE_PATTERN = re.compile('^(?:.*\s)?Device\s(?P<mac>%s)\s(?P<name>.*)' % MAC_ADDRESS_PATTERN)
CONTROLLER_PATTERN = re.compile('^(?:.*\s)?Controller\s(?P<mac>%s)\s(?P<name>.*)' % MAC_ADDRESS_PATTERN)
WAIT_TIME = .75
TRIES = 4
PROFILE = 'a2dp'


_profiles = {
    'a2dp': 'a2dp_sink',
    'hsp': 'headset_head_unit',
    'off': 'off'
}

# CLI Arguments
parser = argparse.ArgumentParser(prog=sys.argv[0])
parser.add_argument('-e', '--echo', action='store_true', default=False,
                    help='If given, the subprocess stdout will be also printed on stdout.')
parser.add_argument('-w', '--wait', default=WAIT_TIME, type=float,
                    help='The seconds to wait for subprocess output, default is: %s' % WAIT_TIME)
parser.add_argument('-t', '--tries', default=TRIES, type=int,
                    help='The number of tries if subprocess is failed. default is: %s' % TRIES)
parser.add_argument('-p', '--profile', default=PROFILE,
                    help='The profile to switch to. available options are: hsp, a2dp. default is: %s' % PROFILE)
parser.add_argument('-V', '--version', action='store_true', help='Show the version.')
parser.add_argument('mac', nargs='?', default=None)


# Exceptions
class SubprocessError(Exception):
    pass


class RetryExceededError(Exception):
    pass


class BluetoothctlProtocol(asyncio.SubprocessProtocol):
    def __init__(self, exit_future, echo=True):
        self.exit_future = exit_future
        self.transport = None
        self.output = None
        self.echo = echo

    def listen_output(self):
        self.output = ''

    def not_listen_output(self):
        self.output = None

    def pipe_data_received(self, fd, raw):
        d = raw.decode()
        if self.echo:
            print(d, end='')

        if self.output is not None:
            self.output += d

    def process_exited(self):
        self.exit_future.set_result(True)

    def connection_made(self, transport):
        self.transport = transport
        print('Connection MADE')

    async def send_command(self, c):
        stdin_transport = self.transport.get_pipe_transport(0)
        # noinspection PyProtectedMember
        stdin_transport._pipe.write(('%s\n' % c).encode())

    async def search_in_output(self, expression, fail_expression=None):
        if self.output is None:
            return None

        for l in self.output.splitlines():
            if fail_expression and re.search(fail_expression, l, re.IGNORECASE):
                raise SubprocessError('Expression "%s" failed with fail pattern: "%s"' % (l, fail_expression))

            if re.search(expression, l, re.IGNORECASE):
                return True

    async def send_and_wait(self, cmd, wait_expression, fail_expression='fail'):
        try:
            self.listen_output()
            await self.send_command(cmd)
            while not await self.search_in_output(wait_expression.lower(), fail_expression=fail_expression):
                await wait()
        finally:
            self.not_listen_output()

    async def disconnect(self, mac):
        print('Disconnecting the device.')
        await self.send_and_wait('disconnect %s' % ':'.join(mac), 'Successful disconnected')

    async def connect(self, mac):
        print('Connecting again.')
        await self.send_and_wait('connect %s' % ':'.join(mac), 'Connection successful')

    async def trust(self, mac):
        await self.send_and_wait('trust %s' % ':'.join(mac), 'trust succeeded')

    async def quit(self):
        await self.send_command('quit')

    async def get_list(self, command, pattern):
        result = set()
        try:
            self.listen_output()
            await self.send_command(command)
            await wait()
            for l in self.output.splitlines():
                m = pattern.match(l)
                if m:
                    result.add(m.groups())
            return sorted(list(result), key=lambda i: i[1])
        finally:
            self.not_listen_output()

    async def list_devices(self):
        return await self.get_list('devices', DEVICE_PATTERN)

    async def list_paired_devices(self):
        return await self.get_list('paired-devices', DEVICE_PATTERN)

    async def list_controllers(self):
        return await self.get_list('list', CONTROLLER_PATTERN)

    async def select_paired_device(self):
        print('Selecting device:')
        devices = await self.list_paired_devices()
        count = len(devices)

        if count < 1:
            raise SubprocessError('There is no connected device.')
        elif count == 1:
            return devices[0]

        for i, d in enumerate(devices):
            print('%d. %s %s' % (i+1, d[0], d[1]))
        print('Select device[1]:')
        selected = input()
        return devices[0 if not selected.strip() else (int(selected) - 1)]


async def wait():
    return await asyncio.sleep(WAIT_TIME)


async def execute_command(cmd, ignore_fail=False):
    p = await asyncio.create_subprocess_shell(cmd, stdout=sb.PIPE, stderr=sb.PIPE)
    stdout, stderr = await p.communicate()
    stdout, stderr = \
        stdout.decode() if stdout is not None else '', \
        stderr.decode() if stderr is not None else ''
    if p.returncode != 0 or stderr.strip() != '':
        message = 'Command: %s failed with status: %s\nstderr: %s' % (cmd, p.returncode, stderr)
        if ignore_fail:
            print('Ignoring: %s' % message)
        else:
            raise SubprocessError(message)
    return stdout


async def execute_find(cmd, pattern, tries=0, fail_safe=False):
    tries = tries or TRIES

    message = 'Cannot find `%s` using `%s`.' % (pattern, cmd)
    retry_message = message + ' Retrying %d more times'
    while True:
        stdout = await execute_command(cmd)
        match = re.search(pattern, stdout)

        if match:
            return match.group()
        elif tries > 0:
            await wait()
            print(retry_message % tries)
            tries -= 1
            continue

        if fail_safe:
            return None

        raise RetryExceededError('Retry times exceeded: %s' % message)


async def find_dev_id(mac, **kw):
    return await execute_find('pactl list cards short', 'bluez_card.%s' % '_'.join(mac), **kw)


async def find_sink(mac, **kw):
    return await execute_find('pacmd list-sinks', 'bluez_sink.%s' % '_'.join(mac), **kw)


async def set_profile(device_id, profile):
    print('Setting the %s profile' % profile)
    try:
        return await execute_command('pactl set-card-profile %s %s' % (device_id, _profiles[profile]))
    except KeyError:
        print('Invalid profile: %s, please select one one of a2dp or hsp.' % profile, file=sys.stderr)
        raise SystemExit(1)


async def set_default_sink(sink):
    print('Updating default sink to %s' % sink)
    return await execute_command('pacmd set-default-sink %s' % sink)


async def move_streams_to_sink(sink):
    streams = await execute_command('pacmd list-sink-inputs | grep "index:"', True)
    for i in streams.split():
        i = ''.join(n for n in i if n.isdigit())
        if i != '':
            print('Moving stream %s to sink' % i)
            await execute_command('pacmd move-sink-input %s %s' % (i, sink))
    return sink


async def main(args):
    global WAIT_TIME, TRIES

    if args.version:
        print(__version__)
        return 0

    mac = args.mac

    # Hacking, Changing the constants!
    WAIT_TIME = args.wait
    TRIES = args.tries

    exit_future = asyncio.Future()
    transport, protocol = await asyncio.get_event_loop().subprocess_exec(
        lambda: BluetoothctlProtocol(exit_future, echo=args.echo), 'bluetoothctl'
    )

    try:

        if mac is None:
            mac, _ = await protocol.select_paired_device()

        mac = mac.split(':' if ':' in mac else '_')
        print('Device MAC: %s' % ':'.join(mac))

        device_id = await find_dev_id(mac, fail_safe=True)
        if device_id is None:
            print('It seems device: %s is not connected yet, trying to connect.' % ':'.join(mac))
            await protocol.trust(mac)
            await protocol.connect(mac)
            device_id = await find_dev_id(mac)

        sink = await find_sink(mac, fail_safe=True)
        if sink is None:
            await set_profile(device_id, args.profile)
            sink = await find_sink(mac)

        print('Device ID: %s' % device_id)
        print('Sink: %s' % sink)

        await set_default_sink(sink)
        await wait()

        await set_profile(device_id, 'off')

        if args.profile is 'a2dp':
            await protocol.disconnect(mac)
            await wait()
            await protocol.connect(mac)

        device_id = await find_dev_id(mac)
        print('Device ID: %s' % device_id)

        await set_profile(device_id, args.profile)
        await set_default_sink(sink)
        await move_streams_to_sink(sink)

    except (SubprocessError, RetryExceededError) as ex:
        print(str(ex), file=sys.stderr)
        return 1
    finally:
        print('Exiting bluetoothctl')
        await protocol.quit()
        await exit_future

        # Close the stdout pipe
        transport.close()

    if args.profile == 'a2dp':
        print('"Enjoy" the HiFi stereo music :)')
    else:
        print('"Enjoy" your headset audio :)')


if __name__ == '__main__':
    sys.exit(asyncio.get_event_loop().run_until_complete(main(parser.parse_args())))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.