ESP32 は、携帯電話などからサウンド データを受信し、コールバック メソッド経由で利用できるようにする Bluetooth A2DP 用の API を提供するマイクロコントローラーです。出力は、SBC 形式からデコードされた PCM データ ストリームです。ドキュメントはここにあります。
I2S は、デジタル オーディオ デバイスを接続するために使用される電気シリアル バス インターフェイス規格です。電子デバイス内の集積回路間で PCM オーディオ データを通信するために使用されます。
したがって、Bluetooth からの入力を I2S 出力に供給するだけです。Espressif の例は Github にあります。
残念ながら、この例では満足できなかったので、Arduino ソフトウェア IDE から簡単に使用できるシンプルなArduino ライブラリに変換することにしました。
このライブラリの名前が示すように、オーディオ ストリーミングのみを提供する A2DP Bluetooth プロトコルをサポートしています。
また、A2DP とともにオーディオ/ビデオ リモート コントロール プロファイル (AVRCP) もサポートします。
ハンズフリー プロファイル (HFP)、ヘッドセット プロファイル (HSP)、および A2DP のないスタンドアロン AVRCP はサポートされていません。
Espressif は従来の I2S API を廃止します。そのため、Arduino v3.0.0 (IDF v5) では、古い I2S 統合は利用できなくなります。アップグレードしない限り、従来の構文は引き続き機能します。
バージョンに依存しない独自の出力 API をサポートするには、AudioTools ライブラリをインストールして使用することをお勧めします。そのため、この新しいアプローチを使用するためにドキュメントとすべての例が更新されました。
ただし、Arduino Print を継承する他のクラス (Arduino ESP32 I2SClass など) に出力することもできます。また、以下で説明するデータ コールバックを使用することもできます。
これは、たとえば独自の Bluetooth スピーカーを構築するために使用できます。
以下は、適切なデフォルト設定のみを使用する最も単純な例です。
# include " AudioTools.h "
# include " BluetoothA2DPSink.h "
I2SStream i2s;
BluetoothA2DPSink a2dp_sink (i2s);
void setup () {
a2dp_sink. start ( " MyMusic " );
}
void loop () {
}
これにより、「MyMusic」という名前の新しい Bluetooth デバイスが作成され、出力は外部 DAC に接続する必要がある次のデフォルトの I2S ピンに送信されます。
これらのデフォルトのピンは従来の API と比べて変更されていることに注意してください。
start
前に独自のピンを簡単に定義できます。
# include " AudioTools.h "
# include " BluetoothA2DPSink.h "
I2SStream i2s;
BluetoothA2DPSink a2dp_sink (i2s);
void setup () {
auto cfg = i2s. defaultConfig ();
cfg. pin_bck = 14 ;
cfg. pin_ws = 15 ;
cfg. pin_data = 22 ;
i2s. begin (cfg);
a2dp_sink. start ( " MyMusic " );
}
void loop () {
}
Arduino ESP32 I2S API を使用することもできます。このために追加のライブラリをインストールする必要はありません。
# include " ESP_I2S.h "
# include " BluetoothA2DPSink.h "
const uint8_t I2S_SCK = 5 ; /* Audio data bit clock */
const uint8_t I2S_WS = 25 ; /* Audio data left and right clock */
const uint8_t I2S_SDOUT = 26 ; /* ESP32 audio data output (to speakers) */
I2SClass i2s;
BluetoothA2DPSink a2dp_sink (i2s);
void setup () {
i2s. setPins (I2S_SCK, I2S_WS, I2S_SDOUT);
if (!i2s. begin (I2S_MODE_STD, 44100 , I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO, I2S_STD_SLOT_BOTH)) {
Serial. println ( " Failed to initialize I2S! " );
while ( 1 ); // do nothing
}
a2dp_sink. start ( " MyMusic " );
}
void loop () {}
この API はインストールされているバージョンにも依存することに注意してください。上記の例は ESP32 >= 3.0.0 の場合です。
AudioTools から AnalogAudioStream を使用して、出力を ESP32 の内部 DAC に直接送信することもできます。
# include " AudioTools.h "
# include " BluetoothA2DPSink.h "
AnalogAudioStream out;
BluetoothA2DPSink a2dp_sink (out);
void setup () {
a2dp_sink. start ( " MyMusic " );
}
void loop () {
}
出力は DAC ピン GPIO25 (チャネル 1) および GPIO26 (チャネル 2) に送られます。
パケットを受信したときに通知を受け取ることができます。 API は、通常 44.1kHz サンプリング レート、2 チャンネル 16 ビット サンプル データとしてフォーマットされた PCM データを使用します。
// In the setup function:
a2dp_sink.set_on_data_received(data_received_callback);
// Then somewhere in your sketch:
void data_received_callback () {
Serial. println ( " Data packet received " );
}
または、パケットにアクセスできます。
// In the setup function:
a2dp_sink.set_stream_reader(read_data_stream);
// Then somewhere in your sketch:
void read_data_stream ( const uint8_t *data, uint32_t length)
{
int16_t *samples = ( int16_t *) data;
uint32_t sample_count = length/ 2 ;
// Do something with the data packet
}
a2dp_sink.set_stream_reader()
メソッドでは、I2S への出力をアクティブにするか非アクティブにするかを定義するオプションのパラメーターを提供できます。つまり、このメソッドを使用して、たとえばa2dp_sink.set_stream_reader(read_data_stream, false)
システムが AVRC メタデータ ( esp_avrc_md_attr_mask_t
) を受信したときに呼び出されるメソッドを登録できます。ここに例があります
void avrc_metadata_callback ( uint8_t data1, const uint8_t *data2) {
Serial. printf ( " AVRC metadata rsp: attribute id 0x%x, %s n " , data1, data2);
}
a2dp_sink.set_avrc_metadata_callback(avrc_metadata_callback);
a2dp_sink.start( " BT " );
デフォルトでは、最も重要な情報を取得する必要がありますが、 set_avrc_metadata_attribute_mask
メソッドを呼び出すことでこれを調整できます。たとえば、タイトルと再生時間だけが必要な場合は、次のように呼び出すことができます。
set_avrc_metadata_attribute_mask (ESP_AVRC_MD_ATTR_TITLE | ESP_AVRC_MD_ATTR_PLAYING_TIME);
A2DP シンクを開始する前に。 data2 は実際には char* 文字列であるため、 ESP_AVRC_MD_ATTR_PLAYING_TIME
メディア継続時間のミリ秒として文書化されている場合でも、計算を行う前に解析する必要があることに注意してください。詳細については、メタデータの例を参照してください。
avrc_metadata_callback
と同様に、ESP IDF v4+ は、 set_avrc_rn_playstatus_callback
、 set_avrc_rn_play_pos_callback
、 set_avrc_rn_track_change_callback
などの選択されたesp_avrc_rn_param_t
コールバックをサポートします。これらは、 esp_avrc_playback_stat_t playback
再生ステータス、 uint32_t play_pos
再生位置、 uint8_t elm_id
それぞれ変更フラグを追跡します。詳細については、playing_status_callbacks の例を参照してください。
A2DP ソースを「制御」するために使用できる次の AVRC コマンドを追加しました。
これを使用して、たとえば Bluetooth スピーカーにオーディオ データを供給できます。
サウンドを生成して、たとえば Bluetooth スピーカーに送信することもできます。
ESP32 A2DP でサポートされているオーディオ コーデックは SBC です。API は、通常 44.1kHz サンプリング レート、2 チャンネル 16 ビット サンプル データとしてフォーマットされた PCM データを使用します。
BluetoothA2DPSource を開始するときは、接続する Bluetooth 名と、サウンド データを生成する「コールバック関数」を渡す必要があります。
# include " BluetoothA2DPSource.h "
BluetoothA2DPSource a2dp_source;
// callback
int32_t get_sound_data (Frame *data, int32_t frameCount) {
// generate your sound data
// return the effective length (in frames) of the generated sound (which usually is identical with the requested len)
// 1 frame is 2 channels * 2 bytes = 4 bytes
return frameCount;
}
void setup () {
a2dp_source. start ( " MyMusic " , get_sound_data);
}
void loop () {
}
例では、sin() 関数を使用してサウンドを生成する実装を見つけることができます。複数の代替 Bluetooth 名を指定することもできます。システムは、利用可能な最初のシステムに接続するだけです。
void setup () {
static std::vector< char *> bt_names = { " MyMusic " , " RadioPlayer " , " MusicPlayer " };
a2dp_source. start (bt_names, get_sound_data);
}
データを uint8_t の単純な配列として直接提供することもできます。
# include " BluetoothA2DPSource.h "
extern const uint8_t StarWars10_raw[];
extern const unsigned int StarWars10_raw_len;
BluetoothA2DPSource a2dp_source;
SoundData *music = new OneChannelSoundData(( int16_t *)StarWars30_raw, StarWars30_raw_len/ 2 );
void setup () {
a2dp_source. start ( " RadioPlayer " );
a2dp_source. write_data (music);
}
void loop () {
}
配列は、たとえば次の方法で準備できます。
パーティション スキーム: Huge App! を使用してコンパイルするとよいでしょう。
上の例では、1 つのチャネルでデータを提供します。これには、2 チャンネル録音よりも使用するスペースがはるかに少ないという利点があり、次のように使用できます。
SoundData *data = new TwoChannelSoundData((Frame*)StarWars10_raw,StarWars10_raw_len/4);
コンストラクターでは、追加のパラメーターを渡すことができます。
TwoChannelSoundData (Frame *data, int32_t frameCount, bool loop= false );
OneChannelSoundData ( int16_t *data, int32_t frameCount, bool loop= false , ChannelInfo channelInfo=Both);
OneChannel8BitSoundData ( int8_t *data, int32_t frameCount, bool loop= false , ChannelInfo channelInfo=Both);
このライブラリは、Arduino の - [ツール] - [コア デバッグ ログ] でアクティブ化できる ESP32 ロガーを使用します。
現在のコードは純粋に ESP-IDF (これも Arduino ESP32 コアによって提供されます) に依存しています。他に依存関係はなく、これには Arduino API が含まれます。
したがって、私たちは以下をサポートします。
ただし、この制限により、提供されている例が制限されます。
プロジェクトのクローンを作成する前に、Wiki にある次の情報をお読みください。
このライブラリはスタンドアロンで使用できますが、私のオーディオツール プロジェクトの一部です。そのため、サウンド エフェクトを使用してこの機能を簡単に強化したり、フィルターを使用したり、代替のオーディオ シンクやオーディオ ソースを使用したり、FFT を実行したりすることができます。ここでは、FFT を使用してオーディオ データを分析する方法の簡単な例を示します。
包括的かつ完全なドキュメントを提供するために多くの時間を費やしました。したがって、Github に新しいものを投稿する前に、まずドキュメントを読み、問題と議論を確認してください。
バグについてのみ問題をオープンし、バグではない場合はディスカッションを使用します: に関する十分な情報を提供します。
他の人があなたの問題を理解し、再現できるようにします。
最後に、何よりも私に電子メールを送ったり、私の個人ウェブサイトに質問を投稿したりしないでください。
このライブラリを使用しているプロジェクトからインスピレーションを得て、プロジェクトをコミュニティと共有してください。
Arduinoの場合、ライブラリをzipとしてダウンロードし、include Library -> zip libraryを呼び出すことができます。または、このプロジェクトを Arduino ライブラリ フォルダーに git clone することもできます。
cd ~ /Documents/Arduino/libraries
git clone https://github.com/pschatzmann/ESP32-A2DP.git
git clone https://github.com/pschatzmann/arduino-audio-tools.git
提供されている例では、audio-tools ライブラリもインストールする必要があります。
他のフレームワークについては、Wiki を参照してください。
変更履歴は Wiki にあります。
このソフトウェアは完全に無料ですが、ご褒美としてご褒美をあげて私を幸せにしてください