mplay

Controllable music player
git clone https://git.sinitax.com/sinitax/mplay
Log | Files | Refs | sfeed.txt

commit 8bd14d100c8d07485d13211e89984e43183b874c
parent 88245add6512f3b9a56d1da40a7dcba2fcd97fed
Author: Louis Burda <quent.burda@gmail.com>
Date:   Sun, 11 Dec 2022 21:59:48 +0100

Pulseaudio simple API version

Diffstat:
M.gitignore | 3++-
MMakefile | 21++++++++++-----------
Mcompile_commands.json | 36++++++++++++++++++------------------
Dsrc/main.c | 88-------------------------------------------------------------------------------
Asrc/mplay.c | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 132 insertions(+), 118 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,2 +1,3 @@ .cache -build/mplay +mplay +compile_commands.json diff --git a/Makefile b/Makefile @@ -1,19 +1,18 @@ CFLAGS = -g -I src -I lib/minimp3/ -LDLIBS = +LDLIBS = -lpulse -lpulse-simple -.PHONY: all clean - -all: build/mplay +all: mplay clean: - rm -rf build + rm -f mplay -build: - mkdir build +mplay: src/mplay.c + $(CC) -o $@ $^ $(CFLAGS) $(LDLIBS) -build/%.o: src/%.c src/%.h | build - $(CC) -o $@ -c $< $(CFLAGS) $(LDLIBS) +install: + install -m755 -t mplay "$(DESTDIR)$(PREFIX)$(BINDIR)" -build/mplay: src/main.c | build - $(CC) -o $@ $^ $(CFLAGS) $(LDLIBS) +uninstall: + rm -f "$(DESTDIR)$(PREFIX)$(BINDIR)/mplay" +.PHONY: all clean install uninstall diff --git a/compile_commands.json b/compile_commands.json @@ -1,18 +1,19 @@ [ - { - "arguments": [ - "cc", - "-c", - "-g", - "-I", - "src", - "-I", - "lib/minimp3/", - "-o", - "build/mplay", - "src/main.c" - ], - "directory": "/snxdata/lib/dev/mplay", - "file": "src/main.c" - } -] -\ No newline at end of file + { + "arguments": [ + "/usr/bin/cc", + "-c", + "-g", + "-I", + "src", + "-I", + "lib/minimp3/", + "-o", + "build/mplay", + "src/mplay.c" + ], + "directory": "/snx/dev/mplay", + "file": "/snx/dev/mplay/src/mplay.c", + "output": "/snx/dev/mplay/build/mplay" + } +] diff --git a/src/main.c b/src/main.c @@ -1,88 +0,0 @@ -#define MINIMP3_IMPLEMENTATION -#include "minimp3.h" -#include "pulse/error.h" -#include "pulse/simple.h" - -#include <stdint.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> - -static uint8_t *read_file(const char *filename, size_t *len); -static void play_file(const char *filename); -static void daemon(void); - -uint8_t * -read_file(const char *filename, size_t *len) -{ - FILE *f; - uint8_t *buf; - size_t start; - - f = fopen(filename, "r"); - if (f == NULL) - ERROR("Failed to open file\n"); - - fseek(f, 0, SEEK_END); - *len = ftell(f) - start; - - buf = malloc(*len); - OOM_CHECK(buf); - - fseek(f, 0, SEEK_SET); - if (fread(buf, 1, *len, f) != len) - ERROR("Failed to read file contents\n"); - - fclose(f); - - return buf; -} - -void -play_file(const char *filename) -{ - static const pa_sample_spec spec = { - .format = PA_SAMPLE_S16LE, - .rate = 44100, - .channels = 2 - }; - mp3dec_frame_info_t info; - mp3d_sample_t sample; - mp3dec_t dec; - pa_simple *stream; - uint8_t *data; - size_t len; - int status, ret; - - data = read_file(filename, &len); - - mp3dec_init(&dec); - - stream = pa_simple_new(NULL, "MPLAY", PA_STREAM_PLAYBACK, NULL, - "playback", &spec, NULL, NULL, &status); - // check status - - while (mp3dec_decode_frame(&dec, data, len, &sample, &info)) { - pa_simple_write(); - } - - ret = pa_simple_drain(stream, &status); - if (!ret) ERROR("Failed to drain rest of audio\n"); - - pa_simple_free(stream); -} - -void -daemon(void) -{ - -} - -int -main(int argc, const char **argv) -{ - if (argc != 2) - ERROR("USAGE: mplay FILE\n"); - - play_file(argv[1]); -} diff --git a/src/mplay.c b/src/mplay.c @@ -0,0 +1,102 @@ +#include "pulse/simple.h" +#include "pulse/volume.h" +#include "pulse/error.h" + +#define MINIMP3_IMPLEMENTATION +#include "minimp3.h" + +#include <sys/mman.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <err.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +static uint8_t *map_file(const char *path, size_t *len); +static void play_file(const char *path); + +static const pa_sample_spec pa_spec = { + .format = PA_SAMPLE_S16LE, + .rate = 44100, + .channels = 2 +}; + +uint8_t * +map_file(const char *path, size_t *len) +{ + struct stat attr; + uint8_t *buf; + int fd; + + fd = open(path, O_RDONLY); + if (fd < 0) err(1, "open %s", path); + + if (fstat(fd, &attr)) + err(1, "fstat %s", path); + + buf = mmap(NULL, attr.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (!buf) err(1, "mmap %s", path); + + *len = attr.st_size; + + close(fd); + + return buf; +} + +void +play_file(const char *filename) +{ + mp3dec_frame_info_t info; + mp3d_sample_t samples[MINIMP3_MAX_SAMPLES_PER_FRAME]; + mp3dec_t mp3d; + pa_simple *pa; + uint8_t *data, *pos; + size_t len; + int pa_err; + int ret; + int cnt; + + data = map_file(filename, &len); + + mp3dec_init(&mp3d); + + pa = pa_simple_new(NULL, "mplay", PA_STREAM_PLAYBACK, NULL, + "playback", &pa_spec, NULL, NULL, &pa_err); + if (!pa) errx(1, "pa_simple_new: %s", pa_strerror(pa_err)); + + pos = data; + while (pos < data + len) { + cnt = mp3dec_decode_frame(&mp3d, pos, len, samples, &info); + if (!cnt && !info.frame_bytes) break; + + pos += info.frame_bytes; + if (!cnt) continue; + + ret = pa_simple_write(pa, samples, + cnt * info.channels * sizeof(mp3d_sample_t), &pa_err); + if (ret) errx(1, "pa_simple_write: %s", pa_strerror(pa_err)); + } + + ret = pa_simple_drain(pa, &pa_err); + if (ret) errx(1, "pa_simple_drain: %s", pa_strerror(pa_err)); + + pa_simple_free(pa); + + munmap(data, len); +} + +int +main(int argc, const char **argv) +{ + if (argc != 2) { + printf("USAGE: mplay FILE\n"); + exit(1); + } + + play_file(argv[1]); +} +