基于kaldi的iOS實時語音識別(本地)+03+音頻采集傳輸

iOS在線識別:http://www.lxweimin.com/u/3c2a0bd52ebc

kaldi靜態庫集成到項目中沒問題后,現在就需要采集音頻發送給解碼器去解碼。

我這里對音頻的傳輸采用的是GStreamer的庫,我們也可以采用自己的方式去傳輸音頻,GStreamer的好處就是能將音頻進行緩存,每次都能有序的從GstBufferSource中去讀取數據進行解碼,我們能控制好這個傳輸的管道,自己實現完全沒問題。

采集

iOS采集音頻的方式有很多種,我這里簡單貼出我采集的方式:

- (void)startCapture {
    self.capture = [AVCaptureSession new];

    AVCaptureDevice *audioDev = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];

    AVCaptureDeviceInput *audioIn = [[AVCaptureDeviceInput alloc] initWithDevice:audioDev error:nil];

    if (![self.capture canAddInput:audioIn]) {
        NSLog(@"不能添加 input device");
        return;
    }

    [self.capture addInput:audioIn];

    AVCaptureAudioDataOutput *audioOut = [AVCaptureAudioDataOutput new];

    [audioOut setSampleBufferDelegate:self queue:dispatch_get_main_queue()];

    if (![self.capture canAddOutput:audioOut]) {
        NSLog(@"不能添加 audio output");
        return;
    }

    [self.capture addOutput:audioOut];
    [audioOut connectionWithMediaType:AVMediaTypeAudio];
    [self.capture startRunning];
}

傳輸

因為傳輸我是用的GStreamer,所以這里需要我們對GStreamer有個了解,不然不知道怎么去跟解碼器串聯起來,出了問題也不知道怎么查。

通俗的說,GStreamer在這里起到了一個管道的作用,連通采集跟解碼器,管道內部有很多的元件,都是對音頻的處理,這個我們不用去關心它是怎么去處理的,我們只需要知道這個管道里面都要需要哪些元件,怎么把他們串起來就可以了。

我這里用的元件有:

  • appsrc:這個是必須的元件,主要是將數據插入管道中
  • decodebin:這個是一個通過decoders和demuxers自動解碼的元件
  • audioresample:使用可配置的窗口方法將原始音頻緩沖區重新采樣到不同的采樣率,以提高質量
  • audioconvert:轉換原始音頻緩沖區之間的各種可能的格式,它支持integer到float轉換,width/depth轉換,signedness和endianness轉換和channel轉換(例如:upmixing和downmixing),以及抖動(dithering)和噪聲(noise-shaping)。
  • tee:將數據分割到多個pad。對數據流1路分成多路的分路器
  • fakesink:一個數據只進不出的sink,吞噬掉其他的流,讓音頻流向前推進
  • queue:數據排隊,直到達到“max-size-buffer”、“max-size-bytes”和/或“max-size-time”屬性指定的限制之一。任何將更多緩沖區推入隊列的嘗試都會阻塞推線程,直到有更多空間可用為止。
  • 自定義的解碼插件:這個是將識別解碼器生成一個GStreamer插件,加入管道中

我們了解了這些元件,通過下面方法創建元件:

gst_element_factory_make(const gchar *factoryname, const gchar *name)

我們獲得了這些元件,接下來我們就需要將這些元件加入到管道(pipeline)中:

gst_bin_add_many(GstBin *bin, GstElement *element_1, ...)

接下來是將每個元件關聯起來:

gst_element_link(GstElement *src, GstElement *dest)

以上我們就做好了這個傳輸數據的管道,有些事件的監聽和狀態的設置也需要在這里做,因為都是一些標準的設置,我這里就不贅述了。

推送數據

采集到數據后,我們可以通過如下方式推送數據:

g_signal_emit_by_name( G_OBJECT(self->appsrc), "push-buffer", buffer, &ret );

這樣數據通過管道就會到達識別解碼器,當然解碼器也要做好接收的準備,這個后面講自定義解碼器插件的時候會說。

至此,我們就完成了音頻的傳輸。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容