mixer/Oss: convert to a class
This commit is contained in:
		| @@ -40,15 +40,24 @@ | |||||||
|  |  | ||||||
| #define VOLUME_MIXER_OSS_DEFAULT		"/dev/mixer" | #define VOLUME_MIXER_OSS_DEFAULT		"/dev/mixer" | ||||||
|  |  | ||||||
| struct oss_mixer { | class OssMixer : public mixer { | ||||||
| 	/** the base mixer class */ |  | ||||||
| 	struct mixer base; |  | ||||||
|  |  | ||||||
| 	const char *device; | 	const char *device; | ||||||
| 	const char *control; | 	const char *control; | ||||||
|  |  | ||||||
| 	int device_fd; | 	int device_fd; | ||||||
| 	int volume_control; | 	int volume_control; | ||||||
|  |  | ||||||
|  | public: | ||||||
|  | 	OssMixer() { | ||||||
|  | 		mixer_init(this, &oss_mixer_plugin); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	bool Configure(const config_param *param, GError **error_r); | ||||||
|  | 	bool Open(GError **error_r); | ||||||
|  | 	void Close(); | ||||||
|  |  | ||||||
|  | 	int GetVolume(GError **error_r); | ||||||
|  | 	bool SetVolume(unsigned volume, GError **error_r); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -75,95 +84,114 @@ oss_find_mixer(const char *name) | |||||||
| 	return -1; | 	return -1; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | inline bool | ||||||
|  | OssMixer::Configure(const config_param *param, GError **error_r) | ||||||
|  | { | ||||||
|  | 	device = config_get_block_string(param, "mixer_device", | ||||||
|  | 					     VOLUME_MIXER_OSS_DEFAULT); | ||||||
|  | 	control = config_get_block_string(param, "mixer_control", NULL); | ||||||
|  |  | ||||||
|  | 	if (control != NULL) { | ||||||
|  | 		volume_control = oss_find_mixer(control); | ||||||
|  | 		if (volume_control < 0) { | ||||||
|  | 			g_set_error(error_r, oss_mixer_quark(), 0, | ||||||
|  | 				    "no such mixer control: %s", control); | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 	} else | ||||||
|  | 		volume_control = SOUND_MIXER_PCM; | ||||||
|  |  | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  |  | ||||||
| static struct mixer * | static struct mixer * | ||||||
| oss_mixer_init(G_GNUC_UNUSED void *ao, const struct config_param *param, | oss_mixer_init(G_GNUC_UNUSED void *ao, const struct config_param *param, | ||||||
| 	       GError **error_r) | 	       GError **error_r) | ||||||
| { | { | ||||||
| 	struct oss_mixer *om = g_new(struct oss_mixer, 1); | 	OssMixer *om = new OssMixer(); | ||||||
|  |  | ||||||
| 	mixer_init(&om->base, &oss_mixer_plugin); | 	if (!om->Configure(param, error_r)) { | ||||||
|  | 		delete om; | ||||||
| 	om->device = config_get_block_string(param, "mixer_device", | 		return nullptr; | ||||||
| 					     VOLUME_MIXER_OSS_DEFAULT); |  | ||||||
| 	om->control = config_get_block_string(param, "mixer_control", NULL); |  | ||||||
|  |  | ||||||
| 	if (om->control != NULL) { |  | ||||||
| 		om->volume_control = oss_find_mixer(om->control); |  | ||||||
| 		if (om->volume_control < 0) { |  | ||||||
| 			g_free(om); |  | ||||||
| 			g_set_error(error_r, oss_mixer_quark(), 0, |  | ||||||
| 				    "no such mixer control: %s", om->control); |  | ||||||
| 			return NULL; |  | ||||||
| 	} | 	} | ||||||
| 	} else |  | ||||||
| 		om->volume_control = SOUND_MIXER_PCM; |  | ||||||
|  |  | ||||||
| 	return &om->base; | 	return om; | ||||||
| } | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
| oss_mixer_finish(struct mixer *data) | oss_mixer_finish(struct mixer *data) | ||||||
| { | { | ||||||
| 	struct oss_mixer *om = (struct oss_mixer *) data; | 	OssMixer *om = (OssMixer *) data; | ||||||
|  |  | ||||||
| 	g_free(om); | 	delete om; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | OssMixer::Close() | ||||||
|  | { | ||||||
|  | 	assert(device_fd >= 0); | ||||||
|  |  | ||||||
|  | 	close(device_fd); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
| oss_mixer_close(struct mixer *data) | oss_mixer_close(struct mixer *data) | ||||||
| { | { | ||||||
| 	struct oss_mixer *om = (struct oss_mixer *) data; | 	OssMixer *om = (OssMixer *) data; | ||||||
|  | 	om->Close(); | ||||||
|  | } | ||||||
|  |  | ||||||
| 	assert(om->device_fd >= 0); | inline bool | ||||||
|  | OssMixer::Open(GError **error_r) | ||||||
|  | { | ||||||
|  | 	device_fd = open_cloexec(device, O_RDONLY, 0); | ||||||
|  | 	if (device_fd < 0) { | ||||||
|  | 		g_set_error(error_r, oss_mixer_quark(), errno, | ||||||
|  | 			    "failed to open %s: %s", | ||||||
|  | 			    device, g_strerror(errno)); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	close(om->device_fd); | 	if (control) { | ||||||
|  | 		int devmask = 0; | ||||||
|  |  | ||||||
|  | 		if (ioctl(device_fd, SOUND_MIXER_READ_DEVMASK, &devmask) < 0) { | ||||||
|  | 			g_set_error(error_r, oss_mixer_quark(), errno, | ||||||
|  | 				    "READ_DEVMASK failed: %s", | ||||||
|  | 				    g_strerror(errno)); | ||||||
|  | 			Close(); | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (((1 << volume_control) & devmask) == 0) { | ||||||
|  | 			g_set_error(error_r, oss_mixer_quark(), 0, | ||||||
|  | 				    "mixer control \"%s\" not usable", | ||||||
|  | 				    control); | ||||||
|  | 			Close(); | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| static bool | static bool | ||||||
| oss_mixer_open(struct mixer *data, GError **error_r) | oss_mixer_open(struct mixer *data, GError **error_r) | ||||||
| { | { | ||||||
| 	struct oss_mixer *om = (struct oss_mixer *) data; | 	OssMixer *om = (OssMixer *) data; | ||||||
|  |  | ||||||
| 	om->device_fd = open_cloexec(om->device, O_RDONLY, 0); | 	return om->Open(error_r); | ||||||
| 	if (om->device_fd < 0) { |  | ||||||
| 		g_set_error(error_r, oss_mixer_quark(), errno, |  | ||||||
| 			    "failed to open %s: %s", |  | ||||||
| 			    om->device, g_strerror(errno)); |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (om->control) { |  | ||||||
| 		int devmask = 0; |  | ||||||
|  |  | ||||||
| 		if (ioctl(om->device_fd, SOUND_MIXER_READ_DEVMASK, &devmask) < 0) { |  | ||||||
| 			g_set_error(error_r, oss_mixer_quark(), errno, |  | ||||||
| 				    "READ_DEVMASK failed: %s", |  | ||||||
| 				    g_strerror(errno)); |  | ||||||
| 			oss_mixer_close(data); |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (((1 << om->volume_control) & devmask) == 0) { |  | ||||||
| 			g_set_error(error_r, oss_mixer_quark(), 0, |  | ||||||
| 				    "mixer control \"%s\" not usable", |  | ||||||
| 				    om->control); |  | ||||||
| 			oss_mixer_close(data); |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return true; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static int | inline int | ||||||
| oss_mixer_get_volume(struct mixer *mixer, GError **error_r) | OssMixer::GetVolume(GError **error_r) | ||||||
| { | { | ||||||
| 	struct oss_mixer *om = (struct oss_mixer *)mixer; |  | ||||||
| 	int left, right, level; | 	int left, right, level; | ||||||
| 	int ret; | 	int ret; | ||||||
|  |  | ||||||
| 	assert(om->device_fd >= 0); | 	assert(device_fd >= 0); | ||||||
|  |  | ||||||
| 	ret = ioctl(om->device_fd, MIXER_READ(om->volume_control), &level); | 	ret = ioctl(device_fd, MIXER_READ(volume_control), &level); | ||||||
| 	if (ret < 0) { | 	if (ret < 0) { | ||||||
| 		g_set_error(error_r, oss_mixer_quark(), errno, | 		g_set_error(error_r, oss_mixer_quark(), errno, | ||||||
| 			    "failed to read OSS volume: %s", | 			    "failed to read OSS volume: %s", | ||||||
| @@ -182,19 +210,25 @@ oss_mixer_get_volume(struct mixer *mixer, GError **error_r) | |||||||
| 	return left; | 	return left; | ||||||
| } | } | ||||||
|  |  | ||||||
| static bool | static int | ||||||
| oss_mixer_set_volume(struct mixer *mixer, unsigned volume, GError **error_r) | oss_mixer_get_volume(struct mixer *mixer, GError **error_r) | ||||||
|  | { | ||||||
|  | 	OssMixer *om = (OssMixer *)mixer; | ||||||
|  | 	return om->GetVolume(error_r); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline bool | ||||||
|  | OssMixer::SetVolume(unsigned volume, GError **error_r) | ||||||
| { | { | ||||||
| 	struct oss_mixer *om = (struct oss_mixer *)mixer; |  | ||||||
| 	int level; | 	int level; | ||||||
| 	int ret; | 	int ret; | ||||||
|  |  | ||||||
| 	assert(om->device_fd >= 0); | 	assert(device_fd >= 0); | ||||||
| 	assert(volume <= 100); | 	assert(volume <= 100); | ||||||
|  |  | ||||||
| 	level = (volume << 8) + volume; | 	level = (volume << 8) + volume; | ||||||
|  |  | ||||||
| 	ret = ioctl(om->device_fd, MIXER_WRITE(om->volume_control), &level); | 	ret = ioctl(device_fd, MIXER_WRITE(volume_control), &level); | ||||||
| 	if (ret < 0) { | 	if (ret < 0) { | ||||||
| 		g_set_error(error_r, oss_mixer_quark(), errno, | 		g_set_error(error_r, oss_mixer_quark(), errno, | ||||||
| 			    "failed to set OSS volume: %s", | 			    "failed to set OSS volume: %s", | ||||||
| @@ -205,6 +239,13 @@ oss_mixer_set_volume(struct mixer *mixer, unsigned volume, GError **error_r) | |||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static bool | ||||||
|  | oss_mixer_set_volume(struct mixer *mixer, unsigned volume, GError **error_r) | ||||||
|  | { | ||||||
|  | 	OssMixer *om = (OssMixer *)mixer; | ||||||
|  | 	return om->SetVolume(volume, error_r); | ||||||
|  | } | ||||||
|  |  | ||||||
| const struct mixer_plugin oss_mixer_plugin = { | const struct mixer_plugin oss_mixer_plugin = { | ||||||
| 	oss_mixer_init, | 	oss_mixer_init, | ||||||
| 	oss_mixer_finish, | 	oss_mixer_finish, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Max Kellermann
					Max Kellermann