Linux 设置默认音频输出设备

Linux 设置默认音频输出设备,第1张

因为我的外接麦克风是通过USB接的电脑还支持监听,设备总是被系统同时加载为输入和输出设备,每次重启都要手动把output改成build-in

解决办法为先用下面的command列出输出设备

尝试选择并设置,例如:

如果成功,在startup application里面添加此命令即可.

这篇文章将为大家详细讲解有关Linux下如何通过两个或多个输出设备播放声音,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

在 Linux 上处理音频是一件很痛苦的事情。Pulseaudio 的出现则是利弊参半。虽然有些事情 Pluseaudio 能够做的更好,但有些事情则反而变得更复杂了。处理音频的输出就是这么一件事情。

如果你想要在 Linux PC 上启用多个音频输出,你只需要利用一个简单的工具就能在一个虚拟j接口上启用另一个声音设备。这比看起来要简单的多。

你可能会好奇为什么要这么做,一个很常见的情况是用电脑在电视上播放视频,你可以同时使用电脑和电视上的扬声器。

安装 Paprefs

实现从多个来源启用音频播放的最简单的方法是是一款名为 “paprefs” 的简单图形化工具。它是 PulseAudio Preferences 的缩写。

该软件包含在 Ubuntu 仓库中,可以直接用 apt 来进行安装。

sudo apt install paprefs

安装后就能狗启动这款程序了。

启动双音频播放

虽然这款工具是图形化的,但作为普通用户在命令行中输入paprefs来启动它恐怕还是要更容易一些。

打开的窗口中有一些标签页,这些标签页内有一些可以调整的设置项。我们这里选择***那个标签页,“Simultaneous Output。”

Paprefs on Ubuntu

这个标签页中没有什么内容,只是一个复选框用来启用该设置。

下一步,打开常规的声音***项。这在不同的发行版中位于不同的位置。在 Ubuntu 上,它位于 GNOME 系统设置内。

Enable Simultaneous Audio

打开声音***项后,选择 “output” 标签页。勾选 “Simultaneous output” 单选按钮。现在它就成了你的默认输出了。

测试一下

用什么东西进行测试随你喜欢,不过播放音乐总是可行的。如果你像前面建议的一样,用视频来进行测试也没问题。

一切顺利的话,你就能从所有连接的设备中听到有声音传出了。

这就是所有要做的事了。此功能最适用于有多个设备(如 HDMI 端口和标准模拟输出)时。你当然也可以试一下其他配置。你还需要注意,只有一个音量控制器,因此你需要根据实际情况调整物理输出设备。

关于“Linux下如何通过两个或多个输出设备播放声音”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

最近工作在调试usb虚拟串口,让其作为kernel启动的调试串口,以及user空间的输入输出控制台。

利用这个机会,学习下printk如何选择往哪个console输出以及user空间下控制台如何选择,记录与此,与大家共享,也方便自己以后翻阅。

Kernel版本号:3.4.55

依照我的思路(还是时间顺序)分了4部分,指定kernel调试console , kernel下printk console的选择 ,kernel下console的注册,user空间console的选择。

一 指定kernel调试console

首先看kernel启动时如何获取和处理指定的console参数。

kernel的启动参数cmdline可以指定调试console,如指定‘console=ttyS0,115200’,

kernel如何解析cmdline,我之前写了一篇博文如下:

http://blog.csdn.net/skyflying2012/article/details/41142801

根据之前的分析,cmdline中有console=xxx,start_kernel中parse_args遍历.init.setup段所有obs_kernel_param。

kernel/printk.c中注册了‘console=’的解析函数console_setup(注册了obs_kernel_param),所以匹配成功,会调用console_setup来解析,如下:

[cpp] view plain copy

static int __init console_setup(char *str)

{

char buf[sizeof(console_cmdline[0].name) + 4]/* 4 for index */

char *s, *options, *brl_options = NULL

int idx

#ifdef CONFIG_A11Y_BRAILLE_CONSOLE

if (!memcmp(str, "brl,", 4)) {

brl_options = ""

str += 4

} else if (!memcmp(str, "brl=", 4)) {

brl_options = str + 4

str = strchr(brl_options, ',')

if (!str) {

printk(KERN_ERR "need port name after brl=\n")

return 1

}

*(str++) = 0

}

#endif

/*

* Decode str into name, index, options.

*/

if (str[0] >= '0' &&str[0] <= '9') {

strcpy(buf, "ttyS")

strncpy(buf + 4, str, sizeof(buf) - 5)

} else {

strncpy(buf, str, sizeof(buf) - 1)

}

buf[sizeof(buf) - 1] = 0

if ((options = strchr(str, ',')) != NULL)

*(options++) = 0

#ifdef __sparc__

if (!strcmp(str, "ttya"))

strcpy(buf, "ttyS0")

if (!strcmp(str, "ttyb"))

strcpy(buf, "ttyS1")

#endif

for (s = buf*ss++)

if ((*s >= '0' &&*s <= '9') || *s == ',')

break

idx = simple_strtoul(s, NULL, 10)

*s = 0

__add_preferred_console(buf, idx, options, brl_options)

console_set_on_cmdline = 1

return 1

}

__setup("console=", console_setup)

参数是console=的值字符串,如“ttyS0,115200”,console_setup对console=参数值做解析,以ttyS0,115200为例,最后buf=“ttyS”,idx=0,options="115200",brl_options=NULL。调用__add_preferred_console如下:

[cpp] view plain copy

/*

* If exclusive_console is non-NULL then only this console is to be printed to.

*/

static struct console *exclusive_console

/*

* Array of consoles built from command line options (console=)

*/

struct console_cmdline

{

charname[8] /* Name of the driver */

int index /* Minor dev. to use*/

char*options /* Options for the driver */

#ifdef CONFIG_A11Y_BRAILLE_CONSOLE

char*brl_options /* Options for braille driver */

#endif

}

#define MAX_CMDLINECONSOLES 8

static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]

static int selected_console = -1

static int preferred_console = -1

int console_set_on_cmdline

EXPORT_SYMBOL(console_set_on_cmdline)

static int __add_preferred_console(char *name, int idx, char *options,

char *brl_options)

{

struct console_cmdline *c

int i

/*

* See if this tty is not yet registered, and

* if we have a slot free.

*/

for (i = 0i <MAX_CMDLINECONSOLES &&console_cmdline[i].name[0]i++)

if (strcmp(console_cmdline[i].name, name) == 0 &&

console_cmdline[i].index == idx) {

if (!brl_options)

selected_console = i

return 0

}

if (i == MAX_CMDLINECONSOLES)

return -E2BIG

if (!brl_options)

selected_console = i

c = &console_cmdline[i]

strlcpy(c->name, name, sizeof(c->name))

c->options = options

#ifdef CONFIG_A11Y_BRAILLE_CONSOLE

c->brl_options = brl_options

#endif

c->index = idx

return 0

}

kernel利用结构体数组console_cmdline[8],最多可支持8个cmdline传入的console参数。

__add_preferred_console将name idx options保存到数组下一个成员console_cmdline结构体中,如果数组中已有重名,则不添加,并置selected_console为最新添加的console_cmdline的下标号。

比如cmdline中有“console=ttyS0,115200 console=ttyS1,9600”

则在console_cmdline[8]数组中console_cmdline[0]代表ttyS0,console_cmdline[1]代表ttyS1,而selected_console=1.

二 kernel下printk console的选择

kernel下调试信息是通过printk输出,如果要kernel正常打印,则需要搞明白printk怎么选择输出的设备。

关于printk的实现原理,我在刚工作的时候写过一篇博文,kernel版本是2.6.21的,但是原理还是一致的,可供参考:

http://blog.csdn.net/skyflying2012/article/details/7970341

printk首先将输出内容添加到一个kernel缓冲区中,叫log_buf,log_buf相关代码如下:

[cpp] view plain copy

#define MAX_CMDLINECONSOLES 8

static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]

static int selected_console = -1

static int preferred_console = -1

int console_set_on_cmdline

EXPORT_SYMBOL(console_set_on_cmdline)

/* Flag: console code may call schedule() */

static int console_may_schedule

#ifdef CONFIG_PRINTK

static char __log_buf[__LOG_BUF_LEN]

static char *log_buf = __log_buf

static int log_buf_len = __LOG_BUF_LEN

static unsigned logged_chars/* Number of chars produced since last read+clear operation */

static int saved_console_loglevel = -1

log_buf的大小由kernel menuconfig配置,我配置的CONFIG_LOG_BUF_SHIFT为17,则log_buf为128k。

printk内容会一直存在log_buf中,log_buf满了之后则会从头在开始存,覆盖掉原来的数据。

根据printk的实现原理,printk最后调用console_unlock实现log_buf数据刷出到指定设备。

这里先不关心printk如何处理log buf数据(比如添加内容级别),只关心printk如何一步步找到指定的输出设备,根据printk.c代码,可以找到如下线索。

printk->vprintk->console_unlock->call_console_drivers->_call_console_drivers->_call_console_drivers->__call_console_drivers

看线索最底层__call_console_drivers代码。如下:

[cpp] view plain copy

/*

* Call the console drivers on a range of log_buf

*/

static void __call_console_drivers(unsigned start, unsigned end)

{

struct console *con

for_each_console(con) {

if (exclusive_console &&con != exclusive_console)

continue

if ((con->flags &CON_ENABLED) &&con->write &&

(cpu_online(smp_processor_id()) ||

(con->flags &CON_ANYTIME)))

con->write(con, &LOG_BUF(start), end - start)

}

}

for_each_console定义如下:

[cpp] view plain copy

/*

* for_each_console() allows you to iterate on each console

*/

#define for_each_console(con) \

for (con = console_driverscon != NULLcon = con->next)

遍历console_drivers链表所有console struct,如果有exclusive_console,则调用与exclusive_console一致console的write,

如果exclusive_console为NULL,则调用所有ENABLE的console的write方法将log buf中start到end的内容发出。

可以看出,execlusive_console来指定printk输出唯一console,如果未指定,则向所有enable的console写。

默认情况下execlusive_console=NULL,所以printk默认是向所有enable的console写!

只有一种情况是指定execlusive_console,就是在console注册时,下面会讲到。

到这里就很明了了,kernel下每次printk打印,首先存log_buf,然后遍历console_drivers,找到合适console(execlusive_console或所有enable的),刷出log。

console_drivers链表的成员是哪里来的,谁会指定execulsive_console?接着来看下一部分,kernel下console的注册


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/8673937.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-19
下一篇 2023-04-19

发表评论

登录后才能评论

评论列表(0条)

保存