1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#pragma once
6
7#include <fbl/ref_ptr.h>
8#include <lib/simple-audio-stream/simple-audio-stream.h>
9#include <zircon/device/audio.h>
10
11#include "vim-audio-utils.h"
12
13// Fwd Decls
14extern "C" {
15    struct vim2_display;
16}
17
18namespace audio {
19namespace vim2 {
20
21class Vim2SpdifAudioStream : public SimpleAudioStream {
22  public:
23    DISALLOW_COPY_ASSIGN_AND_MOVE(Vim2SpdifAudioStream);
24    static void Disable(const Registers& regs);
25
26    uint64_t display_id() const { return display_id_; }
27
28  protected:
29    friend class fbl::RefPtr<Vim2SpdifAudioStream>;
30    friend class SimpleAudioStream;
31
32    Vim2SpdifAudioStream(const vim2_display* display,
33                         fbl::RefPtr<Registers> regs,
34                         fbl::RefPtr<RefCountedVmo> ring_buffer_vmo,
35                         fzl::PinnedVmo pinned_ring_buffer,
36                         uint64_t display_id);
37
38    ~Vim2SpdifAudioStream() override {
39        Shutdown();
40    }
41
42    zx_status_t Init() __TA_REQUIRES(domain_->token()) override;
43    void ShutdownHook() __TA_REQUIRES(domain_->token()) override;
44    void RingBufferShutdown() __TA_REQUIRES(domain_->token()) override;
45
46    zx_status_t ChangeFormat(const audio_proto::StreamSetFmtReq& req)
47        __TA_REQUIRES(domain_->token()) override;
48    zx_status_t SetGain(const audio_proto::SetGainReq& req)
49        __TA_REQUIRES(domain_->token()) override;
50
51    zx_status_t GetBuffer(const audio_proto::RingBufGetBufferReq& req,
52                          uint32_t* out_num_rb_frames,
53                          zx::vmo* out_buffer) __TA_REQUIRES(domain_->token()) override;
54    zx_status_t Start(uint64_t* out_start_time) __TA_REQUIRES(domain_->token()) override;
55    zx_status_t Stop() __TA_REQUIRES(domain_->token()) override;
56
57  private:
58    zx_status_t CreateFormatList() __TA_REQUIRES(domain_->token());
59
60    void Enable();
61    void SetupBuffer();
62    void SetMode(uint32_t frame_rate, audio_sample_format_t fmt);
63    void Mute(bool muted);
64
65    // TODO(johngro) : it is unfortunate that we need to maintain an unmanaged
66    // pointer back to our display in order to configure it properly when
67    // setting audio modes.  In a perfect world, however, we would really not
68    // know much of anything about us.  Instead, we would be able to properly
69    // represent composite device drivers, and this audio code would be running
70    // on its own in a separate devhost and acting as a DAI driver for various
71    // codec drivers.  In this world, HDMI driver would serve as a codec driver,
72    // and it would get first crack at the call to "set format", which would
73    // allow it configure the audio clock recover and audio info-frame as part
74    // of the process of requesting the proper DAI stream to feed the HDMI
75    // transmitter unit in the chip.
76    //
77    // Until that day comes, however, we need a small callback hook into the
78    // display driver to set this up when the high level code asks us to do so.
79    // In order to do that, we need to hold the context pointer to the display
80    // driver instance, which will be passed to us at construction time.  Since
81    // we have no managed pointers, it is the HDMI driver's responsibility to
82    // make certain that its scope outlives our.
83    //
84    const struct vim2_display* const display_;
85    const uint64_t display_id_;
86
87    fbl::RefPtr<Registers> regs_;
88    fbl::RefPtr<RefCountedVmo> ring_buffer_vmo_;
89    fzl::PinnedVmo pinned_ring_buffer_;
90    uint32_t usable_buffer_size_ = 0;
91};
92
93}  // namespace vim2
94}  // namespace audio
95