audio.c 16.5 KB
Newer Older
Y
yygg 已提交
1
/*
2
 * Copyright (c) 2006-2018, RT-Thread Development Team
Y
yygg 已提交
3
 *
4
 * SPDX-License-Identifier: Apache-2.0
5 6 7
 *
 * Change Logs:
 * Date           Author       Notes
8 9
 * 2017-05-09     Urey         first version
 * 2019-07-09     Zero-Free    improve device ops interface and data flows
Y
yygg 已提交
10 11 12
 */

#include <stdio.h>
13
#include <string.h>
Y
yygg 已提交
14 15 16 17
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>

18 19 20
#define DBG_TAG              "audio"
#define DBG_LVL              DBG_INFO
#include <rtdbg.h>
Y
yygg 已提交
21

22
#define MIN(a, b)         ((a) < (b) ? (a) : (b))
23

24 25 26 27 28 29
enum
{
    REPLAY_EVT_NONE  = 0x00,
    REPLAY_EVT_START = 0x01,
    REPLAY_EVT_STOP  = 0x02,
};
30

31
static rt_err_t _audio_send_replay_frame(struct rt_audio_device *audio)
Y
yygg 已提交
32
{
33
    rt_err_t result = RT_EOK;
34 35
    rt_uint8_t *data;
    rt_size_t dst_size, src_size;
36
    rt_uint16_t position, remain_bytes = 0, index = 0;
37
    struct rt_audio_buf_info *buf_info;
Y
yygg 已提交
38

39
    RT_ASSERT(audio != RT_NULL);
Y
yygg 已提交
40

41 42 43 44 45 46 47
    buf_info = &audio->replay->buf_info;
    /* save current pos */
    position = audio->replay->pos;
    dst_size = buf_info->block_size;

    /* check repaly queue is empty */
    if (rt_data_queue_peak(&audio->replay->queue, (const void **)&data, &src_size) != RT_EOK)
Y
yygg 已提交
48
    {
49 50 51
        /* ack stop event */
        if (audio->replay->event & REPLAY_EVT_STOP)
            rt_completion_done(&audio->replay->cmp);
Y
yygg 已提交
52

53 54
        /* send zero frames */
        memset(&buf_info->buffer[audio->replay->pos], 0, dst_size);
Y
yygg 已提交
55

56 57
        audio->replay->pos += dst_size;
        audio->replay->pos %= buf_info->total_size;
Y
yygg 已提交
58
    }
59
    else
Y
yygg 已提交
60
    {
61 62 63 64
        memset(&buf_info->buffer[audio->replay->pos], 0, dst_size);

        /* copy data from memory pool to hardware device fifo */
        while (index < dst_size)
Y
yygg 已提交
65
        {
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
            result = rt_data_queue_peak(&audio->replay->queue, (const void **)&data, &src_size);
            if (result != RT_EOK)
            {
                LOG_D("under run %d, remain %d", audio->replay->pos, remain_bytes);
                audio->replay->pos -= remain_bytes;
                audio->replay->pos += dst_size;
                audio->replay->pos %= buf_info->total_size;
                audio->replay->read_index = 0;
                result = -RT_EEMPTY;
                break;
            }

            remain_bytes = MIN((dst_size - index), (src_size - audio->replay->read_index));
            memcpy(&buf_info->buffer[audio->replay->pos],
                   &data[audio->replay->read_index], remain_bytes);
Y
yygg 已提交
81

82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
            index += remain_bytes;
            audio->replay->read_index += remain_bytes;
            audio->replay->pos += remain_bytes;
            audio->replay->pos %= buf_info->total_size;

            if (audio->replay->read_index == src_size)
            {
                /* free memory */
                audio->replay->read_index = 0;
                rt_data_queue_pop(&audio->replay->queue, (const void **)&data, &src_size, RT_WAITING_NO);
                rt_mp_free(data);

                /* notify transmitted complete. */
                if (audio->parent.tx_complete != RT_NULL)
                    audio->parent.tx_complete(&audio->parent, (void *)data);
            }
Y
yygg 已提交
98 99 100
        }
    }

101 102 103 104 105
    if (audio->ops->transmit != RT_NULL)
    {
        if (audio->ops->transmit(audio, &buf_info->buffer[position], RT_NULL, dst_size) != dst_size)
            result = -RT_ERROR;
    }
Y
yygg 已提交
106

107
    return result;
Y
yygg 已提交
108 109
}

110
static rt_err_t _audio_flush_replay_frame(struct rt_audio_device *audio)
Y
yygg 已提交
111
{
112
    rt_err_t result = RT_EOK;
Y
yygg 已提交
113

114
    if (audio->replay->write_index)
Y
yygg 已提交
115
    {
116 117 118 119
        result = rt_data_queue_push(&audio->replay->queue,
                                    (const void **)audio->replay->write_data,
                                    audio->replay->write_index,
                                    RT_WAITING_FOREVER);
Y
yygg 已提交
120

121
        audio->replay->write_index = 0;
Y
yygg 已提交
122 123
    }

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
    return result;
}

static rt_err_t _aduio_replay_start(struct rt_audio_device *audio)
{
    rt_err_t result = RT_EOK;

    if (audio->replay->activated != RT_TRUE)
    {
        /* start playback hardware device */
        if (audio->ops->start)
            result = audio->ops->start(audio, AUDIO_STREAM_REPLAY);

        audio->replay->activated = RT_TRUE;
        LOG_D("start audio replay device");
    }

    return result;
}

static rt_err_t _aduio_replay_stop(struct rt_audio_device *audio)
{
    rt_err_t result = RT_EOK;

    if (audio->replay->activated == RT_TRUE)
    {
        /* flush replay remian frames */
        _audio_flush_replay_frame(audio);

        /* notify irq(or thread) to stop the data transmission */
        audio->replay->event |= REPLAY_EVT_STOP;

        /* waiting for the remaining data transfer to complete */
        rt_completion_init(&audio->replay->cmp);
        rt_completion_wait(&audio->replay->cmp, RT_WAITING_FOREVER);
        audio->replay->event &= ~REPLAY_EVT_STOP;

        /* stop playback hardware device */
        if (audio->ops->stop)
            result = audio->ops->stop(audio, AUDIO_STREAM_REPLAY);

        audio->replay->activated = RT_FALSE;
        LOG_D("stop audio replay device");
    }

    return result;
}

static rt_err_t _audio_record_start(struct rt_audio_device *audio)
{
    rt_err_t result = RT_EOK;

    if (audio->record->activated != RT_TRUE)
    {
        /* open audio record pipe */
        rt_device_open(RT_DEVICE(&audio->record->pipe), RT_DEVICE_OFLAG_RDONLY);

        /* start record hardware device */
        if (audio->ops->start)
            result = audio->ops->start(audio, AUDIO_STREAM_RECORD);

        audio->record->activated = RT_TRUE;
        LOG_D("start audio record device");
    }

    return result;
}

static rt_err_t _audio_record_stop(struct rt_audio_device *audio)
{
    rt_err_t result = RT_EOK;

    if (audio->record->activated == RT_TRUE)
    {
        /* stop record hardware device */
        if (audio->ops->stop)
            result = audio->ops->stop(audio, AUDIO_STREAM_RECORD);

        /* close audio record pipe */
        rt_device_close(RT_DEVICE(&audio->record->pipe));

        audio->record->activated = RT_FALSE;
        LOG_D("stop audio record device");
    }

    return result;
Y
yygg 已提交
210 211 212 213 214 215 216 217
}

static rt_err_t _audio_dev_init(struct rt_device *dev)
{
    rt_err_t result = RT_EOK;
    struct rt_audio_device *audio;

    RT_ASSERT(dev != RT_NULL);
218
    audio = (struct rt_audio_device *) dev;
Y
yygg 已提交
219 220 221 222 223

    /* initialize replay & record */
    audio->replay = RT_NULL;
    audio->record = RT_NULL;

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
    /* initialize replay */
    if (dev->flag & RT_DEVICE_FLAG_WRONLY)
    {
        struct rt_audio_replay *replay = (struct rt_audio_replay *) rt_malloc(sizeof(struct rt_audio_replay));

        if (replay == RT_NULL)
            return -RT_ENOMEM;
        memset(replay, 0, sizeof(struct rt_audio_replay));

        /* init memory pool for replay */
        replay->mp = rt_mp_create("adu_mp", RT_AUDIO_REPLAY_MP_BLOCK_COUNT, RT_AUDIO_REPLAY_MP_BLOCK_SIZE);
        if (replay->mp == RT_NULL)
        {
            rt_free(replay);
            LOG_E("create memory pool for repaly failed");
            return -RT_ENOMEM;
        }

        /* init queue for audio replay */
        rt_data_queue_init(&replay->queue, CFG_AUDIO_REPLAY_QUEUE_COUNT, 0, RT_NULL);

        /* init mutex lock for audio replay */
        rt_mutex_init(&replay->lock, "replay", RT_IPC_FLAG_PRIO);

        replay->activated = RT_FALSE;
        audio->replay = replay;
    }

    /* initialize record */
    if (dev->flag & RT_DEVICE_FLAG_RDONLY)
    {
        struct rt_audio_record *record = (struct rt_audio_record *) rt_malloc(sizeof(struct rt_audio_record));
        rt_uint8_t *buffer;

        if (record == RT_NULL)
            return -RT_ENOMEM;
        memset(record, 0, sizeof(struct rt_audio_record));

        /* init pipe for record*/
        buffer = rt_malloc(RT_AUDIO_RECORD_PIPE_SIZE);
        if (buffer == RT_NULL)
        {
            rt_free(record);
            LOG_E("malloc memory for for record pipe failed");
            return -RT_ENOMEM;
        }
        rt_audio_pipe_init(&record->pipe, "record",
                           (rt_int32_t)(RT_PIPE_FLAG_FORCE_WR | RT_PIPE_FLAG_BLOCK_RD),
                           buffer,
                           RT_AUDIO_RECORD_PIPE_SIZE);

        record->activated = RT_FALSE;
        audio->record = record;
    }

    /* initialize hardware configuration */
Y
yygg 已提交
280
    if (audio->ops->init)
281 282 283 284 285
        audio->ops->init(audio);

    /* get replay buffer information */
    if (audio->ops->buffer_info)
        audio->ops->buffer_info(audio, &audio->replay->buf_info);
Y
yygg 已提交
286 287 288 289 290 291

    return result;
}

static rt_err_t _audio_dev_open(struct rt_device *dev, rt_uint16_t oflag)
{
292
    struct rt_audio_device *audio;
Y
yygg 已提交
293 294

    RT_ASSERT(dev != RT_NULL);
295
    audio = (struct rt_audio_device *) dev;
Y
yygg 已提交
296 297 298 299 300 301 302 303 304 305 306 307 308

    /* check device flag with the open flag */
    if ((oflag & RT_DEVICE_OFLAG_RDONLY) && !(dev->flag & RT_DEVICE_FLAG_RDONLY))
        return -RT_EIO;
    if ((oflag & RT_DEVICE_OFLAG_WRONLY) && !(dev->flag & RT_DEVICE_FLAG_WRONLY))
        return -RT_EIO;

    /* get open flags */
    dev->open_flag = oflag & 0xff;

    /* initialize the Rx/Tx structure according to open flag */
    if (oflag & RT_DEVICE_OFLAG_WRONLY)
    {
309
        if (audio->replay->activated != RT_TRUE)
310
        {
311 312 313 314 315
            LOG_D("open audio replay device, oflag = %x\n", oflag);
            audio->replay->write_index = 0;
            audio->replay->read_index = 0;
            audio->replay->pos = 0;
            audio->replay->event = REPLAY_EVT_NONE;
316
        }
Y
yygg 已提交
317 318 319
        dev->open_flag |= RT_DEVICE_OFLAG_WRONLY;
    }

320
    if (oflag & RT_DEVICE_OFLAG_RDONLY)
Y
yygg 已提交
321
    {
322 323
        /* open record pipe */
        if (audio->record->activated != RT_TRUE)
324
        {
325
            LOG_D("open audio record device ,oflag = %x\n", oflag);
326

327 328
            _audio_record_start(audio);
            audio->record->activated = RT_TRUE;
329
        }
Y
yygg 已提交
330 331 332 333 334 335 336 337
        dev->open_flag |= RT_DEVICE_OFLAG_RDONLY;
    }

    return RT_EOK;
}

static rt_err_t _audio_dev_close(struct rt_device *dev)
{
338
    struct rt_audio_device *audio;
Y
yygg 已提交
339
    RT_ASSERT(dev != RT_NULL);
340
    audio = (struct rt_audio_device *) dev;
Y
yygg 已提交
341

342
    if (dev->open_flag & RT_DEVICE_OFLAG_WRONLY)
Y
yygg 已提交
343
    {
344 345
        /* stop replay stream */
        _aduio_replay_stop(audio);
346
        dev->open_flag &= ~RT_DEVICE_OFLAG_WRONLY;
Y
yygg 已提交
347 348
    }

349
    if (dev->open_flag & RT_DEVICE_OFLAG_RDONLY)
Y
yygg 已提交
350
    {
351 352
        /* stop record stream */
        _audio_record_stop(audio);
353
        dev->open_flag &= ~RT_DEVICE_OFLAG_RDONLY;
Y
yygg 已提交
354 355
    }

356
    return RT_EOK;
Y
yygg 已提交
357 358 359 360
}

static rt_size_t _audio_dev_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size)
{
361
    struct rt_audio_device *audio;
Y
yygg 已提交
362
    RT_ASSERT(dev != RT_NULL);
363
    audio = (struct rt_audio_device *) dev;
364

365 366
    if (!(dev->open_flag & RT_DEVICE_OFLAG_RDONLY) || (audio->record == RT_NULL))
        return 0;
Y
yygg 已提交
367

368
    return rt_device_read(RT_DEVICE(&audio->record->pipe), pos, buffer, size);
Y
yygg 已提交
369 370 371 372
}

static rt_size_t _audio_dev_write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
373

374
    struct rt_audio_device *audio;
375 376
    rt_uint8_t *ptr;
    rt_uint16_t block_size, remain_bytes, index = 0;
Y
yygg 已提交
377 378

    RT_ASSERT(dev != RT_NULL);
379
    audio = (struct rt_audio_device *) dev;
Y
yygg 已提交
380

381 382
    if (!(dev->open_flag & RT_DEVICE_OFLAG_WRONLY) || (audio->replay == RT_NULL))
        return 0;
Y
yygg 已提交
383

384 385 386 387 388 389
    /* push a new frame to replay data queue */
    ptr = (rt_uint8_t *)buffer;
    block_size = RT_AUDIO_REPLAY_MP_BLOCK_SIZE;

    rt_mutex_take(&audio->replay->lock, RT_WAITING_FOREVER);
    while (index < size)
Y
yygg 已提交
390
    {
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
        /* request buffer from replay memory pool */
        if (audio->replay->write_index % block_size == 0)
        {
            audio->replay->write_data = rt_mp_alloc(audio->replay->mp, RT_WAITING_FOREVER);
            memset(audio->replay->write_data, 0, block_size);
        }

        /* copy data to replay memory pool */
        remain_bytes = MIN((block_size - audio->replay->write_index), (size - index));
        memcpy(&audio->replay->write_data[audio->replay->write_index], &ptr[index], remain_bytes);

        index += remain_bytes;
        audio->replay->write_index += remain_bytes;
        audio->replay->write_index %= block_size;

        if (audio->replay->write_index == 0)
Y
yygg 已提交
407
        {
408 409 410 411
            rt_data_queue_push(&audio->replay->queue,
                               audio->replay->write_data,
                               block_size,
                               RT_WAITING_FOREVER);
Y
yygg 已提交
412 413
        }
    }
414
    rt_mutex_release(&audio->replay->lock);
Y
yygg 已提交
415

416
    /* check replay state */
417
    if (audio->replay->activated != RT_TRUE)
Y
yygg 已提交
418
    {
419
        _aduio_replay_start(audio);
420
        audio->replay->activated = RT_TRUE;
H
heyuanjie87 已提交
421
    }
Y
yygg 已提交
422

423
    return index;
Y
yygg 已提交
424 425
}

B
bernard 已提交
426
static rt_err_t _audio_dev_control(struct rt_device *dev, int cmd, void *args)
Y
yygg 已提交
427
{
428 429
    rt_err_t result = RT_EOK;
    struct rt_audio_device *audio;
Y
yygg 已提交
430
    RT_ASSERT(dev != RT_NULL);
431
    audio = (struct rt_audio_device *) dev;
Y
yygg 已提交
432

433
    /* dev stat...*/
434 435
    switch (cmd)
    {
436 437 438
    case AUDIO_CTL_GETCAPS:
    {
        struct rt_audio_caps *caps = (struct rt_audio_caps *) args;
439

440 441
        LOG_D("AUDIO_CTL_GETCAPS: main_type = %d,sub_type = %d", caps->main_type, caps->sub_type);
        if (audio->ops->getcaps != RT_NULL)
442
        {
443
            result = audio->ops->getcaps(audio, caps);
444 445 446
        }

        break;
447
    }
448

449 450 451
    case AUDIO_CTL_CONFIGURE:
    {
        struct rt_audio_caps *caps = (struct rt_audio_caps *) args;
452

453 454
        LOG_D("AUDIO_CTL_CONFIGURE: main_type = %d,sub_type = %d", caps->main_type, caps->sub_type);
        if (audio->ops->configure != RT_NULL)
455
        {
456
            result = audio->ops->configure(audio, caps);
457
        }
458

459
        break;
460
    }
461

462 463 464
    case AUDIO_CTL_START:
    {
        int stream = *(int *) args;
465

466 467
        LOG_D("AUDIO_CTL_START: stream = %d", stream);
        if (stream == AUDIO_STREAM_REPLAY)
468
        {
469
            result = _aduio_replay_start(audio);
470
        }
471
        else
472
        {
473
            result = _audio_record_start(audio);
474
        }
475

476
        break;
477
    }
478

479 480 481
    case AUDIO_CTL_STOP:
    {
        int stream = *(int *) args;
482

483 484 485 486
        LOG_D("AUDIO_CTL_STOP: stream = %d", stream);
        if (stream == AUDIO_STREAM_REPLAY)
        {
            result = _aduio_replay_stop(audio);
487
        }
488
        else
489
        {
490
            result = _audio_record_stop(audio);
491
        }
492

493
        break;
494 495 496
    }

    default:
497 498
        break;
    }
Y
yygg 已提交
499 500 501 502

    return result;
}

B
Bernard Xiong 已提交
503 504 505 506 507 508 509 510 511 512 513 514
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops audio_ops =
{
    _audio_dev_init,
    _audio_dev_open,
    _audio_dev_close,
    _audio_dev_read,
    _audio_dev_write,
    _audio_dev_control
};
#endif

Y
yygg 已提交
515 516
rt_err_t rt_audio_register(struct rt_audio_device *audio, const char *name, rt_uint32_t flag, void *data)
{
517
    rt_err_t result = RT_EOK;
Y
yygg 已提交
518
    struct rt_device *device;
519

Y
yygg 已提交
520 521 522
    RT_ASSERT(audio != RT_NULL);
    device = &(audio->parent);

523
    device->type = RT_Device_Class_Sound;
Y
yygg 已提交
524 525 526
    device->rx_indicate = RT_NULL;
    device->tx_complete = RT_NULL;

B
Bernard Xiong 已提交
527 528 529 530 531 532 533 534
#ifdef RT_USING_DEVICE_OPS
    device->ops  = &audio_ops;
#else
    device->init    = _audio_dev_init;
    device->open    = _audio_dev_open;
    device->close   = _audio_dev_close;
    device->read    = _audio_dev_read;
    device->write   = _audio_dev_write;
535
    device->control = _audio_dev_control;
B
Bernard Xiong 已提交
536
#endif
537 538
    device->user_data = data;

Y
yygg 已提交
539
    /* register a character device */
540 541 542 543 544 545 546
    result = rt_device_register(device, name, flag | RT_DEVICE_FLAG_REMOVABLE);

    /* initialize audio device */
    if (result == RT_EOK)
        result = rt_device_init(device);

    return result;
Y
yygg 已提交
547 548 549 550
}

int rt_audio_samplerate_to_speed(rt_uint32_t bitValue)
{
551 552 553
    int speed = 0;
    switch (bitValue)
    {
554 555
    case AUDIO_SAMP_RATE_8K:
        speed = 8000;
556
        break;
557 558
    case AUDIO_SAMP_RATE_11K:
        speed = 11052;
559
        break;
560 561
    case AUDIO_SAMP_RATE_16K:
        speed = 16000;
562
        break;
563 564
    case AUDIO_SAMP_RATE_22K:
        speed = 22050;
565
        break;
566 567
    case AUDIO_SAMP_RATE_32K:
        speed = 32000;
568
        break;
569 570
    case AUDIO_SAMP_RATE_44K:
        speed = 44100;
571
        break;
572 573
    case AUDIO_SAMP_RATE_48K:
        speed = 48000;
574
        break;
575 576
    case AUDIO_SAMP_RATE_96K:
        speed = 96000;
577
        break;
578 579
    case AUDIO_SAMP_RATE_128K:
        speed = 128000;
580
        break;
581 582
    case AUDIO_SAMP_RATE_160K:
        speed = 160000;
583
        break;
584 585
    case AUDIO_SAMP_RATE_172K:
        speed = 176400;
586
        break;
587 588
    case AUDIO_SAMP_RATE_192K:
        speed = 192000;
589
        break;
590
    default:
591 592 593

        break;
    }
Y
yygg 已提交
594

595 596
    return speed;
}
Y
yygg 已提交
597

598
void rt_audio_tx_complete(struct rt_audio_device *audio)
Y
yygg 已提交
599
{
600 601
    /* try to send next frame */
    _audio_send_replay_frame(audio);
Y
yygg 已提交
602 603
}

604
void rt_audio_rx_done(struct rt_audio_device *audio, rt_uint8_t *pbuf, rt_size_t len)
Y
yygg 已提交
605
{
606 607
    /* save data to record pipe */
    rt_device_write(RT_DEVICE(&audio->record->pipe), 0, pbuf, len);
Y
yygg 已提交
608 609

    /* invoke callback */
610 611
    if (audio->parent.rx_indicate != RT_NULL)
        audio->parent.rx_indicate(&audio->parent, len);
Y
yygg 已提交
612
}