1bf7ab50dSStephan Aßmus /* 2b543dbc2SStephan Aßmus * Copyright 2003-2010 Haiku Inc. All rights reserved. 3bf7ab50dSStephan Aßmus * Distributed under the terms of the MIT License. 4bf7ab50dSStephan Aßmus * 5bf7ab50dSStephan Aßmus * Authors: 6bf7ab50dSStephan Aßmus * Marcus Overhagen 7bf7ab50dSStephan Aßmus */ 8a9cf57cfSAxel Dörfler 9a9cf57cfSAxel Dörfler 10bf7ab50dSStephan Aßmus #include "MixerCore.h" 11a9cf57cfSAxel Dörfler 12a9cf57cfSAxel Dörfler #include <Buffer.h> 13a9cf57cfSAxel Dörfler #include <string.h> 14a9cf57cfSAxel Dörfler #include <TimeSource.h> // TODO: debug only 15a9cf57cfSAxel Dörfler 16a9cf57cfSAxel Dörfler #include "ByteSwap.h" 17*a79b30c3SStephan Aßmus #include "Interpolate.h" 18bf7ab50dSStephan Aßmus #include "MixerInput.h" 19bf7ab50dSStephan Aßmus #include "MixerUtils.h" 20bf7ab50dSStephan Aßmus #include "Resampler.h" 21bf7ab50dSStephan Aßmus 22678c2017Sbeveloper 23a9cf57cfSAxel Dörfler MixerInput::MixerInput(MixerCore *core, const media_input &input, 24*a79b30c3SStephan Aßmus float mixFrameRate, int32 mixFrameCount, int resamplingAlgorithm) 25a9cf57cfSAxel Dörfler : 26a9cf57cfSAxel Dörfler fCore(core), 272e9d6607Sbeveloper fInput(input), 2888777023Sbeveloper fInputByteSwap(0), 291c237c18Sbeveloper fEnabled(true), 302e9d6607Sbeveloper fInputChannelInfo(0), 312e9d6607Sbeveloper fInputChannelCount(0), 322e9d6607Sbeveloper fInputChannelMask(0), 332e9d6607Sbeveloper fMixerChannelInfo(0), 342e9d6607Sbeveloper fMixerChannelCount(0), 352e9d6607Sbeveloper fMixBuffer(0), 367b0daf5cSbeveloper fMixBufferFrameRate(0), 377b0daf5cSbeveloper fMixBufferFrameCount(0), 38e92593f4Sbeveloper fLastDataFrameWritten(-1), 39af8d0a4dSbeveloper fLastDataAvailableTime(-1), 40e92593f4Sbeveloper fFractionalFrames(0.0), 417b0daf5cSbeveloper fResampler(0), 42356855c3Sbeveloper fRtmPool(0), 439c3be6a5Sbeveloper fUserOverridesChannelDestinations(false) 44678c2017Sbeveloper { 45e6c7c99fSbeveloper fix_multiaudio_format(&fInput.format.u.raw_audio); 46e6c7c99fSbeveloper PRINT_INPUT("MixerInput::MixerInput", fInput); 47e6c7c99fSbeveloper PRINT_CHANNEL_MASK(fInput.format); 482e9d6607Sbeveloper 492e9d6607Sbeveloper ASSERT(fInput.format.u.raw_audio.channel_count > 0); 502e9d6607Sbeveloper 519c3be6a5Sbeveloper for (int i = 0; i < MAX_CHANNEL_TYPES; i++) 529c3be6a5Sbeveloper fChannelTypeGain[i] = 1.0f; 539c3be6a5Sbeveloper 542e9d6607Sbeveloper fInputChannelCount = fInput.format.u.raw_audio.channel_count; 552e9d6607Sbeveloper fInputChannelMask = fInput.format.u.raw_audio.channel_mask; 562e9d6607Sbeveloper fInputChannelInfo = new input_chan_info[fInputChannelCount]; 572e9d6607Sbeveloper 5888777023Sbeveloper // perhaps we need byte swapping 5988777023Sbeveloper if (fInput.format.u.raw_audio.byte_order != B_MEDIA_HOST_ENDIAN) { 60a9cf57cfSAxel Dörfler if (fInput.format.u.raw_audio.format 61a9cf57cfSAxel Dörfler == media_raw_audio_format::B_AUDIO_FLOAT 62a9cf57cfSAxel Dörfler || fInput.format.u.raw_audio.format 63a9cf57cfSAxel Dörfler == media_raw_audio_format::B_AUDIO_INT 64a9cf57cfSAxel Dörfler || fInput.format.u.raw_audio.format 65a9cf57cfSAxel Dörfler == media_raw_audio_format::B_AUDIO_SHORT) { 6688777023Sbeveloper fInputByteSwap = new ByteSwap(fInput.format.u.raw_audio.format); 6788777023Sbeveloper } 6888777023Sbeveloper } 6988777023Sbeveloper 702e9d6607Sbeveloper // initialize fInputChannelInfo 712e9d6607Sbeveloper for (int i = 0; i < fInputChannelCount; i++) { 72b543dbc2SStephan Aßmus fInputChannelInfo[i].buffer_base = 0; 73b543dbc2SStephan Aßmus // will be set by SetMixBufferFormat() 74b543dbc2SStephan Aßmus fInputChannelInfo[i].destination_mask = 0; 75b543dbc2SStephan Aßmus // will be set by UpdateInputChannelDestinationMask() 762e9d6607Sbeveloper fInputChannelInfo[i].gain = 1.0; 772e9d6607Sbeveloper } 782e9d6607Sbeveloper 797b0daf5cSbeveloper // create resamplers 807b0daf5cSbeveloper fResampler = new Resampler * [fInputChannelCount]; 814cc71346SStephan Aßmus for (int i = 0; i < fInputChannelCount; i++) { 82*a79b30c3SStephan Aßmus switch (resamplingAlgorithm) { 83*a79b30c3SStephan Aßmus case 2: 84*a79b30c3SStephan Aßmus fResampler[i] = new Interpolate( 85*a79b30c3SStephan Aßmus fInput.format.u.raw_audio.format, 86b543dbc2SStephan Aßmus media_raw_audio_format::B_AUDIO_FLOAT); 87*a79b30c3SStephan Aßmus break; 88*a79b30c3SStephan Aßmus default: 89*a79b30c3SStephan Aßmus fResampler[i] = new Resampler( 90*a79b30c3SStephan Aßmus fInput.format.u.raw_audio.format, 91*a79b30c3SStephan Aßmus media_raw_audio_format::B_AUDIO_FLOAT); 92*a79b30c3SStephan Aßmus } 934cc71346SStephan Aßmus } 947b0daf5cSbeveloper 95b543dbc2SStephan Aßmus // fMixerChannelInfo and fMixerChannelCount will be initialized by 96b543dbc2SStephan Aßmus // UpdateInputChannelDestinations() 97bf7ab50dSStephan Aßmus SetMixBufferFormat((int32)mixFrameRate, mixFrameCount); 98678c2017Sbeveloper } 99678c2017Sbeveloper 100a9cf57cfSAxel Dörfler 101678c2017Sbeveloper MixerInput::~MixerInput() 102678c2017Sbeveloper { 1032e9d6607Sbeveloper if (fMixBuffer) 1042e9d6607Sbeveloper rtm_free(fMixBuffer); 105356855c3Sbeveloper if (fRtmPool) 106356855c3Sbeveloper rtm_delete_pool(fRtmPool); 1072e9d6607Sbeveloper delete [] fInputChannelInfo; 1082e9d6607Sbeveloper delete [] fMixerChannelInfo; 1097b0daf5cSbeveloper 1107b0daf5cSbeveloper // delete resamplers 1117b0daf5cSbeveloper for (int i = 0; i < fInputChannelCount; i++) 1127b0daf5cSbeveloper delete fResampler[i]; 1137b0daf5cSbeveloper delete [] fResampler; 114db6f1135SJérôme Duval delete fInputByteSwap; 115678c2017Sbeveloper } 116678c2017Sbeveloper 117a9cf57cfSAxel Dörfler 118678c2017Sbeveloper void 119678c2017Sbeveloper MixerInput::BufferReceived(BBuffer *buffer) 120678c2017Sbeveloper { 12188777023Sbeveloper void *data; 12288777023Sbeveloper size_t size; 12388777023Sbeveloper bigtime_t start; 124e92593f4Sbeveloper bigtime_t buffer_duration; 12588777023Sbeveloper 126d5848e21Sbeveloper if (!fMixBuffer) { 127b543dbc2SStephan Aßmus ERROR("MixerInput::BufferReceived: dropped incoming buffer as we " 128b543dbc2SStephan Aßmus "don't have a mix buffer\n"); 129d5848e21Sbeveloper return; 130d5848e21Sbeveloper } 1312e9d6607Sbeveloper 13288777023Sbeveloper data = buffer->Data(); 13388777023Sbeveloper size = buffer->SizeUsed(); 13488777023Sbeveloper start = buffer->Header()->start_time; 135b543dbc2SStephan Aßmus buffer_duration = duration_for_frames(fInput.format.u.raw_audio.frame_rate, 136b543dbc2SStephan Aßmus size / bytes_per_frame(fInput.format.u.raw_audio)); 1378d28117fSbeveloper if (start < 0) { 138b543dbc2SStephan Aßmus ERROR("MixerInput::BufferReceived: buffer with negative start time of " 139b543dbc2SStephan Aßmus "%Ld dropped\n", start); 1408d28117fSbeveloper return; 1418d28117fSbeveloper } 14288777023Sbeveloper 14388777023Sbeveloper // swap the byte order of this buffer, if necessary 14488777023Sbeveloper if (fInputByteSwap) 14588777023Sbeveloper fInputByteSwap->Swap(data, size); 14688777023Sbeveloper 147b543dbc2SStephan Aßmus int offset = frames_for_duration(fMixBufferFrameRate, start) 148b543dbc2SStephan Aßmus % fMixBufferFrameCount; 1498d28117fSbeveloper 150b543dbc2SStephan Aßmus PRINT(4, "MixerInput::BufferReceived: buffer start %10Ld, offset %6d\n", 151b543dbc2SStephan Aßmus start, offset); 1527b0daf5cSbeveloper 153191033efSbeveloper int in_frames = size / bytes_per_frame(fInput.format.u.raw_audio); 154b543dbc2SStephan Aßmus double frames = double(in_frames * fMixBufferFrameRate) 155b543dbc2SStephan Aßmus / fInput.format.u.raw_audio.frame_rate; 156e92593f4Sbeveloper int out_frames = int(frames); 157e92593f4Sbeveloper fFractionalFrames += frames - double(out_frames); 158e92593f4Sbeveloper if (fFractionalFrames >= 1.0) { 159e92593f4Sbeveloper fFractionalFrames -= 1.0; 1607619f562Sbeveloper out_frames++; 161e92593f4Sbeveloper } 162e92593f4Sbeveloper 163e92593f4Sbeveloper // if fLastDataFrameWritten != -1, then we have a valid last position 164e92593f4Sbeveloper // and can do glitch compensation 165e92593f4Sbeveloper if (fLastDataFrameWritten >= 0) { 166b543dbc2SStephan Aßmus int expected_frame = (fLastDataFrameWritten + 1) 167b543dbc2SStephan Aßmus % fMixBufferFrameCount; 168e92593f4Sbeveloper if (offset != expected_frame) { 169e92593f4Sbeveloper // due to rounding and other errors, offset might be off by +/- 1 170e92593f4Sbeveloper // this is not really a bad glitch, we just adjust the position 171e92593f4Sbeveloper if (offset == fLastDataFrameWritten) { 172b543dbc2SStephan Aßmus // printf("MixerInput::BufferReceived: -1 frame GLITCH! last " 173b543dbc2SStephan Aßmus // "frame was %ld, expected frame was %d, new frame is %d\n", 174b543dbc2SStephan Aßmus // fLastDataFrameWritten, expected_frame, offset); 175e92593f4Sbeveloper offset = expected_frame; 176b543dbc2SStephan Aßmus } else if (offset == ((fLastDataFrameWritten + 2) 177b543dbc2SStephan Aßmus % fMixBufferFrameCount)) { 178b543dbc2SStephan Aßmus // printf("MixerInput::BufferReceived: +1 frame GLITCH! last " 179b543dbc2SStephan Aßmus // "frame was %ld, expected frame was %d, new frame is %d\n", 180b543dbc2SStephan Aßmus // fLastDataFrameWritten, expected_frame, offset); 181e92593f4Sbeveloper offset = expected_frame; 182e92593f4Sbeveloper } else { 183b543dbc2SStephan Aßmus printf("MixerInput::BufferReceived: GLITCH! last frame was " 184b543dbc2SStephan Aßmus "%4ld, expected frame was %4d, new frame is %4d\n", 185b543dbc2SStephan Aßmus fLastDataFrameWritten, expected_frame, offset); 186e92593f4Sbeveloper 187e92593f4Sbeveloper if (start > fLastDataAvailableTime) { 188b543dbc2SStephan Aßmus if ((start - fLastDataAvailableTime) 189b543dbc2SStephan Aßmus < (buffer_duration / 10)) { 190e92593f4Sbeveloper // buffer is less than 10% of buffer duration too late 191b543dbc2SStephan Aßmus printf("short glitch, buffer too late, time delta " 192b543dbc2SStephan Aßmus "%Ld\n", start - fLastDataAvailableTime); 193e92593f4Sbeveloper offset = expected_frame; 194e92593f4Sbeveloper out_frames++; 195e92593f4Sbeveloper } else { 196e92593f4Sbeveloper // buffer more than 10% of buffer duration too late 197b543dbc2SStephan Aßmus // TODO: zerofill buffer 198b543dbc2SStephan Aßmus printf("MAJOR glitch, buffer too late, time delta " 199b543dbc2SStephan Aßmus "%Ld\n", start - fLastDataAvailableTime); 200e92593f4Sbeveloper } 201e92593f4Sbeveloper } else { // start <= fLastDataAvailableTime 202e92593f4Sbeveloper // the new buffer is too early 203b543dbc2SStephan Aßmus if ((fLastDataAvailableTime - start) 204b543dbc2SStephan Aßmus < (buffer_duration / 10)) { 205e92593f4Sbeveloper // buffer is less than 10% of buffer duration too early 206b543dbc2SStephan Aßmus printf("short glitch, buffer too early, time delta " 207b543dbc2SStephan Aßmus "%Ld\n", fLastDataAvailableTime - start); 208e92593f4Sbeveloper offset = expected_frame; 209e92593f4Sbeveloper out_frames--; 210e92593f4Sbeveloper if (out_frames < 1) 211e92593f4Sbeveloper out_frames = 1; 212e92593f4Sbeveloper } else { 213e92593f4Sbeveloper // buffer more than 10% of buffer duration too early 214b543dbc2SStephan Aßmus // TODO: zerofill buffer 215b543dbc2SStephan Aßmus printf("MAJOR glitch, buffer too early, time delta " 216b543dbc2SStephan Aßmus "%Ld\n", fLastDataAvailableTime - start); 217e92593f4Sbeveloper } 218e92593f4Sbeveloper } 219e92593f4Sbeveloper } 220e92593f4Sbeveloper } 221e92593f4Sbeveloper } 2227b0daf5cSbeveloper 223b543dbc2SStephan Aßmus // printf("data arrived for %10Ld to %10Ld, storing at frames %ld to %ld\n", 224b543dbc2SStephan Aßmus // start, 225b543dbc2SStephan Aßmus // start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 226b543dbc2SStephan Aßmus // frames_per_buffer(fInput.format.u.raw_audio)), offset, 227b543dbc2SStephan Aßmus // offset + out_frames); 2287b0daf5cSbeveloper if (offset + out_frames > fMixBufferFrameCount) { 2297b0daf5cSbeveloper int out_frames1 = fMixBufferFrameCount - offset; 2307b0daf5cSbeveloper int out_frames2 = out_frames - out_frames1; 2317b0daf5cSbeveloper int in_frames1 = (out_frames1 * in_frames) / out_frames; 2327b0daf5cSbeveloper int in_frames2 = in_frames - in_frames1; 2337b0daf5cSbeveloper 234b543dbc2SStephan Aßmus // printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at " 235b543dbc2SStephan Aßmus // "frames %ld to %ld and %ld to %ld\n", fCore->fTimeSource->Now(), 236b543dbc2SStephan Aßmus // start, 237b543dbc2SStephan Aßmus // start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 238b543dbc2SStephan Aßmus // frames_per_buffer(fInput.format.u.raw_audio)), offset, 239b543dbc2SStephan Aßmus // offset + out_frames1 - 1, 0, out_frames2 - 1); 240b543dbc2SStephan Aßmus PRINT(3, "at %10Ld, data arrived for %10Ld to %10Ld, storing at " 241b543dbc2SStephan Aßmus "frames %ld to %ld and %ld to %ld\n", fCore->fTimeSource->Now(), 242b543dbc2SStephan Aßmus start, 243b543dbc2SStephan Aßmus start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 244b543dbc2SStephan Aßmus frames_per_buffer(fInput.format.u.raw_audio)), offset, 245b543dbc2SStephan Aßmus offset + out_frames1 - 1, 0, out_frames2 - 1); 246b543dbc2SStephan Aßmus PRINT(5, " in_frames %5d, out_frames %5d, in_frames1 %5d, " 247b543dbc2SStephan Aßmus "out_frames1 %5d, in_frames2 %5d, out_frames2 %5d\n", 248b543dbc2SStephan Aßmus in_frames, out_frames, in_frames1, out_frames1, in_frames2, 249b543dbc2SStephan Aßmus out_frames2); 2507b0daf5cSbeveloper 251e92593f4Sbeveloper fLastDataFrameWritten = out_frames2 - 1; 252e92593f4Sbeveloper 253b543dbc2SStephan Aßmus // convert offset from frames into bytes 254b543dbc2SStephan Aßmus offset *= sizeof(float) * fInputChannelCount; 2558d28117fSbeveloper 2567b0daf5cSbeveloper for (int i = 0; i < fInputChannelCount; i++) { 257b543dbc2SStephan Aßmus fResampler[i]->Resample( 258b543dbc2SStephan Aßmus reinterpret_cast<char *>(data) 259b543dbc2SStephan Aßmus + i * bytes_per_sample(fInput.format.u.raw_audio), 260b543dbc2SStephan Aßmus bytes_per_frame(fInput.format.u.raw_audio), in_frames1, 261b543dbc2SStephan Aßmus reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) 262b543dbc2SStephan Aßmus + offset, fInputChannelCount * sizeof(float), out_frames1, 2637b0daf5cSbeveloper fInputChannelInfo[i].gain); 2647b0daf5cSbeveloper 265b543dbc2SStephan Aßmus fResampler[i]->Resample( 266b543dbc2SStephan Aßmus reinterpret_cast<char *>(data) 267b543dbc2SStephan Aßmus + i * bytes_per_sample(fInput.format.u.raw_audio) 268b543dbc2SStephan Aßmus + in_frames1 * bytes_per_frame(fInput.format.u.raw_audio), 269b543dbc2SStephan Aßmus bytes_per_frame(fInput.format.u.raw_audio), in_frames2, 2707b0daf5cSbeveloper reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base), 271b543dbc2SStephan Aßmus fInputChannelCount * sizeof(float), out_frames2, 2727b0daf5cSbeveloper fInputChannelInfo[i].gain); 273e92593f4Sbeveloper 2747b0daf5cSbeveloper } 2757b0daf5cSbeveloper } else { 276b543dbc2SStephan Aßmus // printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at " 277b543dbc2SStephan Aßmus // "frames %ld to %ld\n", fCore->fTimeSource->Now(), start, 278b543dbc2SStephan Aßmus // start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 279b543dbc2SStephan Aßmus // frames_per_buffer(fInput.format.u.raw_audio)), offset, 280b543dbc2SStephan Aßmus // offset + out_frames - 1); 281b543dbc2SStephan Aßmus PRINT(3, "at %10Ld, data arrived for %10Ld to %10Ld, storing at " 282b543dbc2SStephan Aßmus "frames %ld to %ld\n", fCore->fTimeSource->Now(), start, 283b543dbc2SStephan Aßmus start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 284b543dbc2SStephan Aßmus frames_per_buffer(fInput.format.u.raw_audio)), offset, 285b543dbc2SStephan Aßmus offset + out_frames - 1); 286191033efSbeveloper PRINT(5, " in_frames %5d, out_frames %5d\n", in_frames, out_frames); 2878d28117fSbeveloper 288e92593f4Sbeveloper fLastDataFrameWritten = offset + out_frames - 1; 289b543dbc2SStephan Aßmus // convert offset from frames into bytes 290b543dbc2SStephan Aßmus offset *= sizeof(float) * fInputChannelCount; 2917b0daf5cSbeveloper for (int i = 0; i < fInputChannelCount; i++) { 292b543dbc2SStephan Aßmus fResampler[i]->Resample( 293b543dbc2SStephan Aßmus reinterpret_cast<char *>(data) 294b543dbc2SStephan Aßmus + i * bytes_per_sample(fInput.format.u.raw_audio), 295b543dbc2SStephan Aßmus bytes_per_frame(fInput.format.u.raw_audio), in_frames, 296b543dbc2SStephan Aßmus reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) 297b543dbc2SStephan Aßmus + offset, fInputChannelCount * sizeof(float), 298b543dbc2SStephan Aßmus out_frames, fInputChannelInfo[i].gain); 2997b0daf5cSbeveloper } 3007b0daf5cSbeveloper } 301e92593f4Sbeveloper fLastDataAvailableTime = start + buffer_duration; 302678c2017Sbeveloper } 3037ee2c804Sbeveloper 304bf7ab50dSStephan Aßmus 3057ee2c804Sbeveloper media_input & 3067ee2c804Sbeveloper MixerInput::MediaInput() 3077ee2c804Sbeveloper { 3087ee2c804Sbeveloper return fInput; 3097ee2c804Sbeveloper } 310e6c7c99fSbeveloper 311bf7ab50dSStephan Aßmus 312e6c7c99fSbeveloper int32 313e6c7c99fSbeveloper MixerInput::ID() 314e6c7c99fSbeveloper { 315e6c7c99fSbeveloper return fInput.destination.id; 316e6c7c99fSbeveloper } 317e6c7c99fSbeveloper 318bf7ab50dSStephan Aßmus 319d91580cdSbeveloper int 320fae6ce82Sbeveloper MixerInput::GetInputChannelCount() 321fae6ce82Sbeveloper { 322fae6ce82Sbeveloper return fInputChannelCount; 323fae6ce82Sbeveloper } 324fae6ce82Sbeveloper 325bf7ab50dSStephan Aßmus 3262e9d6607Sbeveloper void 3279c3be6a5Sbeveloper MixerInput::AddInputChannelDestination(int channel, int destination_type) 3282e9d6607Sbeveloper { 3299c3be6a5Sbeveloper uint32 mask = ChannelTypeToChannelMask(destination_type); 330e6c7c99fSbeveloper 3312e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 3322e9d6607Sbeveloper return; 3332e9d6607Sbeveloper 3342e9d6607Sbeveloper // test if it is already set 3359c3be6a5Sbeveloper if (fInputChannelInfo[channel].destination_mask & mask) 3362e9d6607Sbeveloper return; 3372e9d6607Sbeveloper 3389c3be6a5Sbeveloper // verify that no other channel has id 3399c3be6a5Sbeveloper if (-1 != GetInputChannelForDestination(destination_type)) { 340b543dbc2SStephan Aßmus ERROR("MixerInput::AddInputChannelDestination: destination_type %d " 341b543dbc2SStephan Aßmus "already assigned to channel %d\n", destination_type, 342b543dbc2SStephan Aßmus GetInputChannelForDestination(destination_type)); 3439c3be6a5Sbeveloper return; 3449c3be6a5Sbeveloper } 3452e9d6607Sbeveloper 3462e9d6607Sbeveloper // add it to specified channel 3479c3be6a5Sbeveloper fInputChannelInfo[channel].destination_mask |= mask; 3482e9d6607Sbeveloper 3499c3be6a5Sbeveloper fUserOverridesChannelDestinations = true; 3509c3be6a5Sbeveloper UpdateInputChannelDestinations(); 3512e9d6607Sbeveloper } 3522e9d6607Sbeveloper 353a9cf57cfSAxel Dörfler 3542e9d6607Sbeveloper void 3559c3be6a5Sbeveloper MixerInput::RemoveInputChannelDestination(int channel, int destination_type) 3562e9d6607Sbeveloper { 3579c3be6a5Sbeveloper uint32 mask = ChannelTypeToChannelMask(destination_type); 3582e9d6607Sbeveloper 3592e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 3602e9d6607Sbeveloper return; 3612e9d6607Sbeveloper 3622e9d6607Sbeveloper // test if it is really set 3639c3be6a5Sbeveloper if ((fInputChannelInfo[channel].destination_mask & mask) == 0) 3642e9d6607Sbeveloper return; 3652e9d6607Sbeveloper 3662e9d6607Sbeveloper // remove it from specified channel 3679c3be6a5Sbeveloper fInputChannelInfo[channel].destination_mask &= ~mask; 3682e9d6607Sbeveloper 3699c3be6a5Sbeveloper fUserOverridesChannelDestinations = true; 3709c3be6a5Sbeveloper UpdateInputChannelDestinations(); 3712e9d6607Sbeveloper } 3722e9d6607Sbeveloper 373a9cf57cfSAxel Dörfler 3749c3be6a5Sbeveloper bool 3759c3be6a5Sbeveloper MixerInput::HasInputChannelDestination(int channel, int destination_type) 3762e9d6607Sbeveloper { 3772e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 3789c3be6a5Sbeveloper return false; 3799c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 3809c3be6a5Sbeveloper return false; 381b543dbc2SStephan Aßmus return fInputChannelInfo[channel].destination_mask 382b543dbc2SStephan Aßmus & ChannelTypeToChannelMask(destination_type); 3832e9d6607Sbeveloper } 3842e9d6607Sbeveloper 385a9cf57cfSAxel Dörfler 3869c3be6a5Sbeveloper int 3879c3be6a5Sbeveloper MixerInput::GetInputChannelForDestination(int destination_type) 3889c3be6a5Sbeveloper { 3899c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 3909c3be6a5Sbeveloper return -1; 3919c3be6a5Sbeveloper uint32 mask = ChannelTypeToChannelMask(destination_type); 3929c3be6a5Sbeveloper for (int chan = 0; chan < fInputChannelCount; chan++) { 3939c3be6a5Sbeveloper if (fInputChannelInfo[chan].destination_mask & mask) 3949c3be6a5Sbeveloper return chan; 3959c3be6a5Sbeveloper } 3969c3be6a5Sbeveloper return -1; 3979c3be6a5Sbeveloper } 3989c3be6a5Sbeveloper 399a9cf57cfSAxel Dörfler 4009c3be6a5Sbeveloper int 4012e9d6607Sbeveloper MixerInput::GetInputChannelType(int channel) 4022e9d6607Sbeveloper { 4032e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 4042e9d6607Sbeveloper return 0; 4059c3be6a5Sbeveloper return GetChannelType(channel, fInputChannelMask); 4062e9d6607Sbeveloper } 4072e9d6607Sbeveloper 408a9cf57cfSAxel Dörfler 4092e9d6607Sbeveloper void 4102e9d6607Sbeveloper MixerInput::SetInputChannelGain(int channel, float gain) 4112e9d6607Sbeveloper { 4122e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 4132e9d6607Sbeveloper return; 4142e9d6607Sbeveloper if (gain < 0.0f) 4152e9d6607Sbeveloper gain = 0.0f; 4162e9d6607Sbeveloper 4172e9d6607Sbeveloper fInputChannelInfo[channel].gain = gain; 4182e9d6607Sbeveloper } 4192e9d6607Sbeveloper 420a9cf57cfSAxel Dörfler 4212e9d6607Sbeveloper float 4222e9d6607Sbeveloper MixerInput::GetInputChannelGain(int channel) 4232e9d6607Sbeveloper { 4242e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 4252e9d6607Sbeveloper return 0.0f; 4262e9d6607Sbeveloper return fInputChannelInfo[channel].gain; 4272e9d6607Sbeveloper } 4282e9d6607Sbeveloper 429a9cf57cfSAxel Dörfler 4302e9d6607Sbeveloper void 4319c3be6a5Sbeveloper MixerInput::UpdateInputChannelDestinationMask() 4322e9d6607Sbeveloper { 4332e9d6607Sbeveloper // is the user already messed with the assignmens, don't do anything. 4349c3be6a5Sbeveloper if (fUserOverridesChannelDestinations) 4352e9d6607Sbeveloper return; 4362e9d6607Sbeveloper 4379c3be6a5Sbeveloper TRACE("UpdateInputChannelDestinationMask: enter\n"); 4382e9d6607Sbeveloper 439806cf560Sbeveloper // first apply a 1:1 mapping 440b543dbc2SStephan Aßmus for (int i = 0; i < fInputChannelCount; i++) { 441b543dbc2SStephan Aßmus fInputChannelInfo[i].destination_mask = GetChannelMask(i, 442b543dbc2SStephan Aßmus fInputChannelMask); 443b543dbc2SStephan Aßmus } 444806cf560Sbeveloper 445806cf560Sbeveloper // specialize this, depending on the available physical output channels 446643e1b2eSbeveloper if (fCore->OutputChannelCount() <= 2) { 447643e1b2eSbeveloper // less or equal two channels 448b543dbc2SStephan Aßmus if (fInputChannelCount == 1 449b543dbc2SStephan Aßmus && (GetChannelMask(0, fInputChannelMask) 450b543dbc2SStephan Aßmus & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) { 451ab276ac8Sbeveloper fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO; 452806cf560Sbeveloper } 453643e1b2eSbeveloper } else { 454643e1b2eSbeveloper // more than two channel output card 455b543dbc2SStephan Aßmus if (fInputChannelCount == 1 456b543dbc2SStephan Aßmus && (GetChannelMask(0, fInputChannelMask) 457b543dbc2SStephan Aßmus & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) { 458ab276ac8Sbeveloper fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO; 459806cf560Sbeveloper } 460b543dbc2SStephan Aßmus if (fInputChannelCount == 2 461b543dbc2SStephan Aßmus && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_LEFT)) { 462b543dbc2SStephan Aßmus fInputChannelInfo[0].destination_mask 463b543dbc2SStephan Aßmus = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT; 464806cf560Sbeveloper } 465b543dbc2SStephan Aßmus if (fInputChannelCount == 2 466b543dbc2SStephan Aßmus && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_RIGHT)) { 467b543dbc2SStephan Aßmus fInputChannelInfo[0].destination_mask 468b543dbc2SStephan Aßmus = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT; 469806cf560Sbeveloper } 470b543dbc2SStephan Aßmus if (fInputChannelCount == 2 471b543dbc2SStephan Aßmus && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_LEFT)) { 472b543dbc2SStephan Aßmus fInputChannelInfo[1].destination_mask 473b543dbc2SStephan Aßmus = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT; 474806cf560Sbeveloper } 475b543dbc2SStephan Aßmus if (fInputChannelCount == 2 476b543dbc2SStephan Aßmus && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_RIGHT)) { 477b543dbc2SStephan Aßmus fInputChannelInfo[1].destination_mask 478b543dbc2SStephan Aßmus = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT; 479806cf560Sbeveloper } 4802e9d6607Sbeveloper } 4812e9d6607Sbeveloper 482b543dbc2SStephan Aßmus for (int i = 0; i < fInputChannelCount; i++) { 483b543dbc2SStephan Aßmus TRACE("UpdateInputChannelDestinationMask: input channel %d, " 484b543dbc2SStephan Aßmus "destination_mask 0x%08lX, base %p, gain %.3f\n", i, 485b543dbc2SStephan Aßmus fInputChannelInfo[i].destination_mask, 486b543dbc2SStephan Aßmus fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain); 487b543dbc2SStephan Aßmus } 4889c3be6a5Sbeveloper TRACE("UpdateInputChannelDestinationMask: leave\n"); 4892e9d6607Sbeveloper } 4902e9d6607Sbeveloper 491a9cf57cfSAxel Dörfler 4922e9d6607Sbeveloper void 4939c3be6a5Sbeveloper MixerInput::UpdateInputChannelDestinations() 4942e9d6607Sbeveloper { 495d91580cdSbeveloper int channel_count; 4962e9d6607Sbeveloper uint32 all_bits; 4972e9d6607Sbeveloper uint32 mask; 4982e9d6607Sbeveloper 4999c3be6a5Sbeveloper TRACE("UpdateInputChannelDestinations: enter\n"); 500b543dbc2SStephan Aßmus for (int i = 0; i < fInputChannelCount; i++) { 501b543dbc2SStephan Aßmus TRACE("UpdateInputChannelDestinations: input channel %d, " 502b543dbc2SStephan Aßmus "destination_mask 0x%08lX, base %p, gain %.3f\n", i, 503b543dbc2SStephan Aßmus fInputChannelInfo[i].destination_mask, 504b543dbc2SStephan Aßmus fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain); 505b543dbc2SStephan Aßmus } 5062e9d6607Sbeveloper 5072e9d6607Sbeveloper all_bits = 0; 5082e9d6607Sbeveloper for (int i = 0; i < fInputChannelCount; i++) 5099c3be6a5Sbeveloper all_bits |= fInputChannelInfo[i].destination_mask; 5102e9d6607Sbeveloper 511d91580cdSbeveloper TRACE("UpdateInputChannelDestinations: all_bits = %08lx\n", all_bits); 5122e9d6607Sbeveloper 5132e9d6607Sbeveloper channel_count = count_nonzero_bits(all_bits); 514b543dbc2SStephan Aßmus TRACE("UpdateInputChannelDestinations: %d input channels, %d mixer " 515b543dbc2SStephan Aßmus "channels (%d old)\n", fInputChannelCount, channel_count, 516b543dbc2SStephan Aßmus fMixerChannelCount); 5172e9d6607Sbeveloper if (channel_count != fMixerChannelCount) { 5189c3be6a5Sbeveloper delete [] fMixerChannelInfo; 5192e9d6607Sbeveloper fMixerChannelInfo = new mixer_chan_info[channel_count]; 5202e9d6607Sbeveloper fMixerChannelCount = channel_count; 5212e9d6607Sbeveloper } 5222e9d6607Sbeveloper 5232e9d6607Sbeveloper // assign each mixer channel one type 5249c3be6a5Sbeveloper // and the gain from the fChannelTypeGain[] 525d91580cdSbeveloper mask = 1; 526d91580cdSbeveloper for (int i = 0; i < fMixerChannelCount; i++) { 5272e9d6607Sbeveloper while (mask != 0 && (all_bits & mask) == 0) 5282e9d6607Sbeveloper mask <<= 1; 5299c3be6a5Sbeveloper fMixerChannelInfo[i].destination_type = ChannelMaskToChannelType(mask); 530b543dbc2SStephan Aßmus fMixerChannelInfo[i].destination_gain 531b543dbc2SStephan Aßmus = fChannelTypeGain[fMixerChannelInfo[i].destination_type]; 5322e9d6607Sbeveloper mask <<= 1; 5332e9d6607Sbeveloper } 5342e9d6607Sbeveloper 5352e9d6607Sbeveloper // assign buffer_base pointer for each mixer channel 5362e9d6607Sbeveloper for (int i = 0; i < fMixerChannelCount; i++) { 5372e9d6607Sbeveloper int j; 5382e9d6607Sbeveloper for (j = 0; j < fInputChannelCount; j++) { 539b543dbc2SStephan Aßmus if (fInputChannelInfo[j].destination_mask 540b543dbc2SStephan Aßmus & ChannelTypeToChannelMask( 541b543dbc2SStephan Aßmus fMixerChannelInfo[i].destination_type)) { 542b543dbc2SStephan Aßmus fMixerChannelInfo[i].buffer_base = fMixBuffer ? &fMixBuffer[j] 543b543dbc2SStephan Aßmus : 0; 5442e9d6607Sbeveloper break; 5452e9d6607Sbeveloper } 5462e9d6607Sbeveloper } 5472e9d6607Sbeveloper if (j == fInputChannelCount) { 548a2ca4723Sbeveloper ERROR("buffer assignment failed for mixer chan %d\n", i); 5492e9d6607Sbeveloper fMixerChannelInfo[i].buffer_base = fMixBuffer; 5502e9d6607Sbeveloper } 5512e9d6607Sbeveloper } 5522e9d6607Sbeveloper 553b543dbc2SStephan Aßmus for (int i = 0; i < fMixerChannelCount; i++) { 554b543dbc2SStephan Aßmus TRACE("UpdateInputChannelDestinations: mixer channel %d, type %2d, " 555b543dbc2SStephan Aßmus "base %p, gain %.3f\n", i, fMixerChannelInfo[i].destination_type, 556b543dbc2SStephan Aßmus fMixerChannelInfo[i].buffer_base, 557b543dbc2SStephan Aßmus fMixerChannelInfo[i].destination_gain); 558b543dbc2SStephan Aßmus } 5592e9d6607Sbeveloper 5609c3be6a5Sbeveloper TRACE("UpdateInputChannelDestinations: leave\n"); 5612e9d6607Sbeveloper } 562bf7ab50dSStephan Aßmus 563a9cf57cfSAxel Dörfler 564bf7ab50dSStephan Aßmus // Note: The following code is outcommented on purpose 565bf7ab50dSStephan Aßmus // and is about to be modified at a later point 56669517c15Sbeveloper /* 5672e9d6607Sbeveloper void 568b543dbc2SStephan Aßmus MixerInput::SetInputChannelDestinationGain(int channel, int destination_type, 569b543dbc2SStephan Aßmus float gain) 5702e9d6607Sbeveloper { 571b543dbc2SStephan Aßmus TRACE("SetInputChannelDestinationGain: channel %d, destination_type %d, 572b543dbc2SStephan Aßmus gain %.4f\n", channel, destination_type, gain); 5739c3be6a5Sbeveloper // we don't need the channel, as each destination_type can only exist 5749c3be6a5Sbeveloper // once for each MixerInput, but we use it for parameter validation 5759c3be6a5Sbeveloper // and to have a interface similar to MixerOutput 5762e9d6607Sbeveloper if (channel < 0 || channel >= fMixerChannelCount) 5772e9d6607Sbeveloper return; 5789c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 5799c3be6a5Sbeveloper return; 5802e9d6607Sbeveloper if (gain < 0.0f) 5812e9d6607Sbeveloper gain = 0.0f; 5829c3be6a5Sbeveloper fChannelTypeGain[destination_type] = gain; 5839c3be6a5Sbeveloper for (int i = 0; i < fMixerChannelCount; i++) { 5849c3be6a5Sbeveloper if (fMixerChannelInfo[i].destination_type == destination_type) { 5859c3be6a5Sbeveloper fMixerChannelInfo[i].destination_gain = gain; 5869c3be6a5Sbeveloper return; 5879c3be6a5Sbeveloper } 5889c3be6a5Sbeveloper } 5892e9d6607Sbeveloper } 5902e9d6607Sbeveloper 591a9cf57cfSAxel Dörfler 5922e9d6607Sbeveloper float 5939c3be6a5Sbeveloper MixerInput::GetInputChannelDestinationGain(int channel, int destination_type) 5942e9d6607Sbeveloper { 5959c3be6a5Sbeveloper // we don't need the channel, as each destination_type can only exist 5969c3be6a5Sbeveloper // once for each MixerInput, but we use it for parameter validation 5979c3be6a5Sbeveloper // and to have a interface similar to MixerOutput 5982e9d6607Sbeveloper if (channel < 0 || channel >= fMixerChannelCount) 5999c3be6a5Sbeveloper return 0.0f; 6009c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 6019c3be6a5Sbeveloper return 0.0f; 6029c3be6a5Sbeveloper return fChannelTypeGain[destination_type]; 6032e9d6607Sbeveloper } 60469517c15Sbeveloper */ 60569517c15Sbeveloper 606a9cf57cfSAxel Dörfler 60769517c15Sbeveloper void 60869517c15Sbeveloper MixerInput::SetMixerChannelGain(int mixer_channel, float gain) 60969517c15Sbeveloper { 61069517c15Sbeveloper if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount) 61169517c15Sbeveloper return; 61269517c15Sbeveloper if (gain < 0.0f) 61369517c15Sbeveloper gain = 0.0f; 61469517c15Sbeveloper 61569517c15Sbeveloper fMixerChannelInfo[mixer_channel].destination_gain = gain; 61669517c15Sbeveloper fChannelTypeGain[fMixerChannelInfo[mixer_channel].destination_type] = gain; 61769517c15Sbeveloper } 61869517c15Sbeveloper 619a9cf57cfSAxel Dörfler 62069517c15Sbeveloper float 62169517c15Sbeveloper MixerInput::GetMixerChannelGain(int mixer_channel) 62269517c15Sbeveloper { 62369517c15Sbeveloper if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount) 62469517c15Sbeveloper return 0.0; 62569517c15Sbeveloper return fMixerChannelInfo[mixer_channel].destination_gain; 62669517c15Sbeveloper } 62769517c15Sbeveloper 628a9cf57cfSAxel Dörfler 62969517c15Sbeveloper int 63069517c15Sbeveloper MixerInput::GetMixerChannelType(int mixer_channel) 63169517c15Sbeveloper { 63269517c15Sbeveloper if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount) 63369517c15Sbeveloper return -1; 63469517c15Sbeveloper return fMixerChannelInfo[mixer_channel].destination_type; 63569517c15Sbeveloper } 6362e9d6607Sbeveloper 637a9cf57cfSAxel Dörfler 6382e9d6607Sbeveloper void 6391c237c18Sbeveloper MixerInput::SetEnabled(bool yesno) 6401c237c18Sbeveloper { 6411c237c18Sbeveloper fEnabled = yesno; 6421c237c18Sbeveloper } 6431c237c18Sbeveloper 644a9cf57cfSAxel Dörfler 6451c237c18Sbeveloper bool 6461c237c18Sbeveloper MixerInput::IsEnabled() 6471c237c18Sbeveloper { 6481c237c18Sbeveloper return fEnabled; 6491c237c18Sbeveloper } 6501c237c18Sbeveloper 651a9cf57cfSAxel Dörfler 6521c237c18Sbeveloper void 6538d28117fSbeveloper MixerInput::SetMixBufferFormat(int32 framerate, int32 frames) 6542e9d6607Sbeveloper { 655a9cf57cfSAxel Dörfler TRACE("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n", 656a9cf57cfSAxel Dörfler framerate, frames); 657d5848e21Sbeveloper 6587b0daf5cSbeveloper fMixBufferFrameRate = framerate; 659a9cf57cfSAxel Dörfler fDebugMixBufferFrames = frames; 6602e9d6607Sbeveloper 661d5848e21Sbeveloper // frames and/or framerate can be 0 (if no output is connected) 662d5848e21Sbeveloper if (framerate == 0 || frames == 0) { 663a9cf57cfSAxel Dörfler if (fMixBuffer != NULL) { 664d5848e21Sbeveloper rtm_free(fMixBuffer); 665a9cf57cfSAxel Dörfler fMixBuffer = NULL; 666d5848e21Sbeveloper } 667d5848e21Sbeveloper for (int i = 0; i < fInputChannelCount; i++) 668d5848e21Sbeveloper fInputChannelInfo[i].buffer_base = 0; 669d5848e21Sbeveloper fMixBufferFrameCount = 0; 670d5848e21Sbeveloper 6719c3be6a5Sbeveloper UpdateInputChannelDestinationMask(); 6729c3be6a5Sbeveloper UpdateInputChannelDestinations(); 673d5848e21Sbeveloper return; 674d5848e21Sbeveloper } 6757b0daf5cSbeveloper 6767b0daf5cSbeveloper // make fMixBufferFrameCount an integral multiple of frames, 6777b0daf5cSbeveloper // but at least 3 times duration of our input buffer 6787b0daf5cSbeveloper // and at least 2 times duration of the output buffer 679b543dbc2SStephan Aßmus bigtime_t inputBufferLength = duration_for_frames( 680b543dbc2SStephan Aßmus fInput.format.u.raw_audio.frame_rate, 681b543dbc2SStephan Aßmus frames_per_buffer(fInput.format.u.raw_audio)); 6827b0daf5cSbeveloper bigtime_t outputBufferLength = duration_for_frames(framerate, frames); 683b543dbc2SStephan Aßmus bigtime_t mixerBufferLength 684b543dbc2SStephan Aßmus = max_c(3 * inputBufferLength, 2 * outputBufferLength); 6857b0daf5cSbeveloper int temp = frames_for_duration(framerate, mixerBufferLength); 6867b0daf5cSbeveloper fMixBufferFrameCount = ((temp / frames) + 1) * frames; 6877b0daf5cSbeveloper 688a2ca4723Sbeveloper TRACE(" inputBufferLength %10Ld\n", inputBufferLength); 689a2ca4723Sbeveloper TRACE(" outputBufferLength %10Ld\n", outputBufferLength); 690a2ca4723Sbeveloper TRACE(" mixerBufferLength %10Ld\n", mixerBufferLength); 691d91580cdSbeveloper TRACE(" fMixBufferFrameCount %10d\n", fMixBufferFrameCount); 6927b0daf5cSbeveloper 6938d28117fSbeveloper ASSERT((fMixBufferFrameCount % frames) == 0); 6948d28117fSbeveloper 695e92593f4Sbeveloper fLastDataFrameWritten = -1; 696e92593f4Sbeveloper fFractionalFrames = 0.0; 697e92593f4Sbeveloper 6982e9d6607Sbeveloper rtm_free(fMixBuffer); 699356855c3Sbeveloper rtm_delete_pool(fRtmPool); 700a9cf57cfSAxel Dörfler 7017b0daf5cSbeveloper int size = sizeof(float) * fInputChannelCount * fMixBufferFrameCount; 702a9cf57cfSAxel Dörfler if (rtm_create_pool(&fRtmPool, size) != B_OK) 703a9cf57cfSAxel Dörfler fRtmPool = NULL; 704a9cf57cfSAxel Dörfler 705356855c3Sbeveloper fMixBuffer = (float*)rtm_alloc(fRtmPool, size); 706a9cf57cfSAxel Dörfler if (fMixBuffer == NULL) 707a9cf57cfSAxel Dörfler return; 7087b0daf5cSbeveloper 7097b0daf5cSbeveloper memset(fMixBuffer, 0, size); 7102e9d6607Sbeveloper 7112e9d6607Sbeveloper for (int i = 0; i < fInputChannelCount; i++) 7127b0daf5cSbeveloper fInputChannelInfo[i].buffer_base = &fMixBuffer[i]; 713d5848e21Sbeveloper 7149c3be6a5Sbeveloper UpdateInputChannelDestinationMask(); 7159c3be6a5Sbeveloper UpdateInputChannelDestinations(); 7162e9d6607Sbeveloper } 717