Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset d26233c in mainline


Ignore:
Timestamp:
2013-04-07T09:46:59Z (9 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master
Children:
e1d2f0e
Parents:
7db073f
Message:

wavplay: implement parallel playback

Location:
uspace/app/wavplay
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/wavplay/Makefile

    r7db073f rd26233c  
    3232LIBS = \
    3333        $(LIBHOUND_PREFIX)/libhound.a \
    34         $(LIBDRV_PREFIX)/libdrv.a
     34        $(LIBDRV_PREFIX)/libdrv.a \
     35        $(LIBPCM_PREFIX)/libpcm.a
    3536
    3637EXTRA_CFLAGS = \
  • uspace/app/wavplay/main.c

    r7db073f rd26233c  
    3737#include <errno.h>
    3838#include <fibril_synch.h>
     39#include <malloc.h>
    3940#include <str_error.h>
    4041#include <stdio.h>
     
    4647#include "wave.h"
    4748
    48 #define BUFFER_SIZE (32 * 1024)
    49 
    50 
    51 static int hplay(const char *filename)
    52 {
    53         printf("Hound playback: %s\n", filename);
     49#define READ_SIZE  (32 * 1024)
     50#define STREAM_BUFFER_SIZE   (64 * 1024)
     51
     52static int hplay_ctx(hound_context_t *ctx, const char *filename)
     53{
     54        printf("Hound context playback: %s\n", filename);
    5455        FILE *source = fopen(filename, "rb");
    5556        if (!source) {
     
    7374                return EINVAL;
    7475        }
     76
     77        hound_stream_t *stream = hound_stream_create(ctx,
     78            HOUND_STREAM_DRAIN_ON_EXIT, format, STREAM_BUFFER_SIZE);
     79
     80        char * buffer = malloc(READ_SIZE);
     81        if (!buffer) {
     82                fclose(source);
     83                return ENOMEM;
     84        }
     85        while ((read = fread(buffer, sizeof(char), READ_SIZE, source)) > 0) {
     86                ret = hound_stream_write(stream, buffer, read);
     87                if (ret != EOK) {
     88                        printf("Failed to write to hound stream: %s\n",
     89                            str_error(ret));
     90                        break;
     91                }
     92        }
     93        free(buffer);
     94        fclose(source);
     95        return ret;
     96}
     97
     98static int hplay(const char *filename)
     99{
     100        printf("Hound playback: %s\n", filename);
     101        FILE *source = fopen(filename, "rb");
     102        if (!source) {
     103                printf("Failed to open file %s\n", filename);
     104                return EINVAL;
     105        }
     106        wave_header_t header;
     107        size_t read = fread(&header, sizeof(header), 1, source);
     108        if (read != 1) {
     109                printf("Failed to read WAV header: %zu\n", read);
     110                fclose(source);
     111                return EIO;
     112        }
     113        pcm_format_t format;
     114        const char *error;
     115        int ret = wav_parse_header(&header, NULL, NULL, &format.channels,
     116            &format.sampling_rate, &format.sample_format, &error);
     117        if (ret != EOK) {
     118                printf("Error parsing wav header: %s.\n", error);
     119                fclose(source);
     120                return EINVAL;
     121        }
    75122        hound_context_t *hound = hound_context_create_playback(filename,
    76             format, BUFFER_SIZE * 2);
     123            format, STREAM_BUFFER_SIZE);
    77124        if (!hound) {
    78125                printf("Failed to create HOUND context\n");
     
    89136                return ret;
    90137        }
    91         static char buffer[BUFFER_SIZE];
    92         while ((read = fread(buffer, sizeof(char), BUFFER_SIZE, source)) > 0) {
     138        static char buffer[READ_SIZE];
     139        while ((read = fread(buffer, sizeof(char), READ_SIZE, source)) > 0) {
    93140                ret = hound_write_main_stream(hound, buffer, read);
    94141                if (ret != EOK) {
     
    103150}
    104151
     152typedef struct {
     153        hound_context_t *ctx;
     154        atomic_t *count;
     155        const char *file;
     156} fib_play_t;
     157
     158static int play_wrapper(void *arg)
     159{
     160        assert(arg);
     161        fib_play_t *p = arg;
     162        const int ret = hplay_ctx(p->ctx, p->file);
     163        atomic_dec(p->count);
     164        free(arg);
     165        return ret;
     166}
     167
    105168static const struct option opts[] = {
    106169        {"device", required_argument, 0, 'd'},
     170        {"parallel", no_argument, 0, 'p'},
    107171        {"record", no_argument, 0, 'r'},
    108172        {"help", no_argument, 0, 'h'},
     
    119183        printf("\t -d, --device\t Use specified device instead of the sound "
    120184            "service. Use location path or a special device `default'\n");
     185        printf("\t -p, --parallel\t Play given files in parallel instead of "
     186            "sequentially (does not work with -d).\n");
    121187}
    122188
     
    125191        const char *device = "default";
    126192        int idx = 0;
    127         bool direct = false, record = false;
     193        bool direct = false, record = false, parallel = false;
    128194        optind = 0;
    129195        int ret = 0;
    130196        while (ret != -1) {
    131                 ret = getopt_long(argc, argv, "d:rh", opts, &idx);
     197                ret = getopt_long(argc, argv, "d:prh", opts, &idx);
    132198                switch (ret) {
    133199                case 'd':
     
    138204                        record = true;
    139205                        break;
     206                case 'p':
     207                        parallel = true;
     208                        break;
    140209                case 'h':
    141210                        print_help(*argv);
     
    144213        }
    145214
     215        if (parallel && direct) {
     216                printf("Parallel playback is available only if using sound "
     217                    "server (no -d)\n");
     218                print_help(*argv);
     219                return 1;
     220        }
     221
    146222        if (optind == argc) {
    147223                printf("Not enough arguments.\n");
    148224                print_help(*argv);
    149225                return 1;
     226        }
     227
     228        hound_context_t *hound_ctx = NULL;
     229        atomic_t playcount;
     230        atomic_set(&playcount, 0);
     231        if (parallel) {
     232                hound_ctx = hound_context_create_playback("wavplay",
     233                    AUDIO_FORMAT_DEFAULT, STREAM_BUFFER_SIZE);
     234                if (!hound_ctx) {
     235                        printf("Failed to create global hound context\n");
     236                        return 1;
     237                }
     238                const int ret = hound_context_connect_target(hound_ctx,
     239                    HOUND_DEFAULT_TARGET);
     240                if (ret != EOK) {
     241                        printf("Failed to connect hound context to default "
     242                           "target.\n");
     243                        hound_context_destroy(hound_ctx);
     244                        return 1;
     245                }
    150246        }
    151247
     
    162258                        dplay(device, file);
    163259                } else {
    164                         hplay(file);
    165                 }
    166         }
     260                        if (parallel) {
     261                                fib_play_t *data = malloc(sizeof(fib_play_t));
     262                                if (!data) {
     263                                        printf("Playback of %s failed.\n",
     264                                                file);
     265                                        continue;
     266                                }
     267                                data->file = file;
     268                                data->count = &playcount;
     269                                data->ctx = hound_ctx;
     270                                fid_t fid = fibril_create(play_wrapper, data);
     271                                atomic_inc(&playcount);
     272                                fibril_add_ready(fid);
     273                        } else {
     274                                hplay(file);
     275                        }
     276                }
     277        }
     278
     279        while (atomic_get(&playcount) > 0)
     280                async_usleep(1000000);
     281
     282        if (hound_ctx)
     283                hound_context_destroy(hound_ctx);
    167284        return 0;
    168285}
Note: See TracChangeset for help on using the changeset viewer.